日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dp 树状数组 逆序元组

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dp 树状数组 逆序元组 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

wmq的隊伍

發布時間: 2017年4月9日 17:06?? 最后更新: 2017年4月9日 17:07?? 時間限制: 2000ms?? 內存限制: 512M

描述

交大上課需要打卡,于是在上課前的幾分鐘打卡機前往往會排起長隊。

平時早睡早起早早打卡的wmq昨晚失眠,今天起晚了,于是他也加入了打卡隊伍中。

這個時候,wmq發現了神奇的現象,打卡隊伍可以按人們的身高看成一個隊列,左邊是隊頭,右邊是隊尾。

對于隊列a1...an,wmq想知道其中存在多少的有序k元組l1...lk

使得1l1<l2<...<lkn,并且有al1>al2>...>alk

輸入

輸入有多組數據

第一行是一個正整數T1T15,代表數據組數

每組數據第一行是兩個正整數nk1n2?1041kmin(n,100)

n?代表隊列的人數,k??的含義見題面

接下來一行有n個正整數,代表1n的一個排列,表示隊伍的身高情況

輸出

對于每組數據,輸出一個整數,代表有序k元組的個數

考慮到數字可能很大,將答案對109+7取模之后輸出

樣例輸入1?復制 3 2 2 1 2 2 2 2 1 22 3 1 2 3 4 5 16 6 7 8 9 10 19 11 12 14 15 17 18 21 22 20 13 樣例輸出1 0 1 8

很容易想到用動態規劃的方式來解決在這道題目,我們用dp[i][j][t]來表示在前i個隊伍里,以t結尾的j元祖有多少個

這樣的話轉移就是dp[i][j][t] = sum(dp[i-1][j-1][m])其中m > t

但這樣的話空間復雜度是4*10^10,我們發現dp[i]只與dp[i-1]有關,因此可以重復利用,所以 省掉一維只用dp[j][t]來表示就好了,這樣的話復雜度降低到了2*10^6可以忍受了。

另外時間復雜度,因為i要從1循環到2*10^4 ,元組長度 要循環100次,比t大的m的循環最差也要循環2*10^4,因此總的時間復雜度為4*10^10顯然不能通過。

我們要利用這道題目很重要的一點,隊列中的人是1到n的一個排列,因此n最大不超過2*10^4,我們可以想到用樹狀數組的方法來求出sum(dp[i-1][j-1][m])的值,只需要logn的復雜度就行了,注意要為每個j元組都要開一個樹狀數組

int bitree[maxk][maxn];//為j元組開辟樹狀數組

這樣的話sum(dp[i-1][j-1][m]) 的值實際上就等于sum(j-1,n) - sum(j-1,t);t是隊伍中的第i個元素

注意爆int!別忘記取mod,比賽時候因為這兩個低級錯誤WA了6發。。。。。55555

#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define int long long const int maxk = 105; const int maxn = 20005; int bitree[maxk][maxn]; int dp[maxk][maxn];//dp[i][j]表示 i元組,末尾為j的元組個數 const int MOD = 1e9 + 7; int n,k; inline int lowbit(int x){return x&(-x); } void add(int tid,int pos,int val){while(pos <= n){bitree[tid][pos] += val;pos += lowbit(pos);} } int sum(int tid,int pos){int res = 0;while(pos > 0){res += bitree[tid][pos];pos -= lowbit(pos);}return res; } void init(){memset(bitree,0,sizeof(bitree));memset(dp,0,sizeof(dp)); } main(){int T;scanf("%lld",&T);while(T--){init();scanf("%lld%lld",&n,&k);int now;for(int i = 1;i <= n;i++){scanf("%lld",&now);dp[1][now] = 1;add(1,now,1);for(int j = 2;j <= k;j++){dp[j][now] = (sum(j-1,n) - sum(j-1,now))% MOD;add(j,now,dp[j][now]);}}int ans = 0;for(int i = 1;i <= n;i++){ans = (ans + dp[k][i]) % MOD;}printf("%lld\n",ans);}return 0; }



創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的dp 树状数组 逆序元组的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。