正题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542
题目大意
求序列A有多少个长度为M的递增子序列。
解题思路
用fi,jfi,j表示长度为i,以AjAj结尾的序列的个数。然后显然得出动态转移方程通过上一次从任意一个地方转移,动态转移方程:
fi,j=∑k<j,Ak<Ajfi−1,kfi,j=∑k<j,Ak<Ajfi−1,k
我们可以用树状数组储存和维护k。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 2010
#define lowbit(x) x&-x
#define BPM 1000000007
using namespace std;
int t[N],a[N],f[N][N],n,m,l,uiqe[N],ans,ts;
void change(int x,int k)
{while(x<=l){t[x]=(t[x]+k)%BPM;x+=lowbit(x);}
}
int ask(int x)
{int sum=0;while(x){sum=(sum+t[x])%BPM;x-=lowbit(x);}return sum;
}
int main()
{scanf("%d",&ts);for(int ti=1;ti<=ts;ti++){scanf("%d%d",&n,&m);a[0]=-2147483647;uiqe[n+1]=a[0];for(int i=1;i<=n;i++)scanf("%d",&a[i]),uiqe[i]=a[i];sort(uiqe+1,uiqe+2+n);l=unique(uiqe+1,uiqe+1+n)-(uiqe+1);for(int i=0;i<=n;i++)a[i]=lower_bound(uiqe+1,uiqe+1+l,a[i])-uiqe;//以上为离散化memset(f,0,sizeof(f));f[0][0]=1;ans=0;for(int i=1;i<=m;i++){memset(t,0,sizeof(t));change(a[0],f[i-1][0]);//修改for(int j=1;j<=n;j++){f[i][j]=ask(a[j]-1);//询问和change(a[j],f[i-1][j]);//维护和if(i==m) ans=(ans+f[i][j])%BPM;}}printf("Case #%d: %d\n",ti,ans);}
}