HDU5542 The Battle of Chibi

题意

给出长度为n的序列,问这个序列中有多少个长度为m的单调递增子序列。
\(1\le M\le N\le 1000\)

分析

用F[i,j]表示前j个数构成以Aj为结尾的数列中,长度为i的严格递增子序列有多少个

\[F[i,j]=\sum_{k<j\wedge A_k<A_j}F[i-1,k] \]

复杂度\(O(mn^2)\)

观察到决策集合的变化一是只增不减,二是有一个前缀范围,用树状数组维护转移即可。时间复杂度\(O(mn\log n)\)

代码

#include<iostream>
#include<algorithm>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;

co int N=1e3+1,INF=0x3f3f3f3f,mod=1e9+7;
int n,m,a[N],b[N],c[N],f[N][N],num;
void add(int x,int y){
	for(;x<=n+1;x+=x&-x)
		c[x]=(c[x]+y)%mod;
}
int ask(int x){
	int ans=0;
	for(;x;x-=x&-x)
		ans=(ans+c[x])%mod;
	return ans;
}
void The_Battle_of_Chibi(){
	read(n),read(m);
	for(int i=1;i<=n;++i) b[i]=read(a[i]);
	sort(b+1,b+n+1);
	for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+n+1,a[i])-b+1;
	a[0]=f[0][0]=1;
	for(int i=1;i<=m;++i){
		fill(c+1,c+n+2,0);
		add(1,f[i-1][0]);
		for(int j=1;j<=n;++j){
			f[i][j]=ask(a[j]-1);
			add(a[j],f[i-1][j]);
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i) ans=(ans+f[m][i])%mod;
	printf("Case #%d: %d\n",++num,ans);
}
int main(){
	for(int t=read<int>();t--;) The_Battle_of_Chibi();
	return 0;
}

posted on 2019-04-17 16:56  autoint  阅读(143)  评论(0编辑  收藏  举报

导航