UVA12983 The Battle of Chibi 樹狀陣列+DP
阿新 • • 發佈:2018-11-08
先容蒟蒻吐槽一波:模數看錯調了一兩小時。。。
題意:
要你在一個長度為n的序列中找到長度為m的嚴格上升子序列的個數,然後答案對1e9+7取模。
舉個例子:
5 3
1 3 4 2 5
那麼符合條件的序列就有: 1 3 4 ,1 2 5, 1 3 5 ,1 4 5, 3 4 5, 答案就是5。
既然和上升子序列有關,那麼就是DP了。
注意我這裡設的i,j有點不一樣,表示的是
前j個數,以a[j]結尾的,嚴格上升子序列長度為i的方案數。(反過來也OK,只不過待會BIT就得開兩維)
容易得到狀態轉移方程:f[i][j]=sigma (f[i-1][k]), 0<=k<j 且 a[k]<a[j]。
那麼的話n3的暴力是很容易打的。
但是如果只是n3題目就沒多大意義了。
我們考慮優化:
顯然對於一個j我們只關心他前面的滿足 a[k]<a[j] 的所有的方案數的和。
那麼這就可以直接建立一個權值樹狀陣列,(注意到ai<=1e9 離散化即可)
對於每一個數先查詢之前的比他小的,統計一下答案。
再把自己的值插入自己的對應的位置就可以了。
可以發現由於我們的 i 是在外層迴圈,即已經限制了長度, 所以內部更新時i-1不變。
所以只要直接建一維的BIT就好了,不要考慮把長度也記下來,只是每次i++後,清空BIT。
#include <bits/stdc++.h> usingnamespace std; inline int gi () { int x=0,w=0; char ch=0; while (!(ch>='0' && ch<='9')) {if (ch=='-') w=1; ch=getchar ();} while (ch>='0' && ch<='9') x= (x<<3)+(x<<1)+(ch^48), ch=getchar (); return w?-x:x; } #define LL long long #define INF 0x3f3f3f3f; #defineRGI register int #define lowbit(x) x&-x const int N=1010; const int Mod=1e9+7; LL Ans,BIT[N],f[N][N]; int T,n,m,tot,a[N],b[N]; inline void New_Case () { memset (f, 0 ,sizeof (f)); f[0][0]=1, Ans=0, a[0]=1; } inline void Modify (int x, int val) { for (;x<=n;x+=lowbit(x)) BIT[x]=(BIT[x]+val%Mod)%Mod; } inline LL Query (int x) { LL sum=0; for (;x;x-=lowbit(x)) sum=(sum+BIT[x])%Mod; return sum; } int main () { T=gi (); for (RGI id=1;id<=T;++id) { RGI i,j; New_Case (); n=gi (), m=gi (); for (i=1;i<=n;++i) a[i]=b[i]=gi (); sort (b+1, b+n+1); for (i=1;i<=n;++i) a[i]=lower_bound (b+1, b+n+1, a[i])-b+1; for (i=1;i<=m;++i) { memset (BIT, 0, sizeof (BIT)); Modify (a[0], f[i-1][0]); for (j=1;j<=n;++j) { f[i][j]=Query (a[j]-1); Modify (a[j], f[i-1][j]%Mod); } } for (i=1;i<=n;++i) Ans= (Ans+f[m][i])%Mod; printf ("Case #%d: %lld\n", id, Ans); } return 0; }