UVA12983 The Battle of Chibi 树状数组+DP
先容蒟蒻吐槽一波:模数看错调了一两小时。。。 题意: 要你在一个长度为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> using namespace 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; #define RGI 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,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: %lldn",id,Ans); } return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |