JXOI2017 数列

数列

九条可怜手上有一个长度为 \(n\) 的整数数列 \(r_i\) ,她现在想要构造一个长度为 \(n\) 的,满足如下条件的整数数列 \(A\)

  • \(1\leq A_i \leq r_i\)
  • 对于任意 \(3 \leq i \leq n\),令 \(R\)\(A_1\)\(A_{i-2}\) 中大于等于 \(A_{i-1}\) 的最小值,\(L\)\(A_1\)\(A_{i-2}\) 中小于等于 \(A_{i-1}\) 的最大值。\(A_i\) 必须满足 \(L \leq A_i \leq R\)。如果不存在大于等于 \(A_{i-1}\) 的,那 么 \(R = +\infty\);如果不存在小于等于 \(A_{i-1}\) 的,那么 \(L = −\infty\)

现在可怜想要知道共有多少不同的数列满足这个条件。两个数列 \(A\)\(B\) 是不同的当且仅当至少存在一个位置 \(i\) 满足 \(A_i \neq B_i\)

\(n\leq 50,r\leq 150\)

题解

http://jklover.hs-blog.cf/2020/06/06/Loj-2273-数列/#more

dp 计数.

不难发现,合法的选择区间会在选一个数之后不断收缩,将它作为状态记录下来 dp 即可.

\(dp(i,l,r,k)\) 表示考虑了前 \(i\) 个数,下个数合法的选择区间为 \([l,r]\) , 最后一个数的值为 \(k\) 的方案数.

转移时,对于 \([l,l],[l+1,k-1],[k,k],[k+1,r-1],[r,r]\) 这几段分别转移,每一段内转移到新的 \(l,r\) 是一样的.

于是修改差分就可以完成 \(O(1)\) 转移,注意处理 \(l,r\) 不存在等特殊情况,时间复杂度 \(O(n\cdot r^3)\) .

CO int N=160;
int t[N],f[2][N][N][N];

IN void trans(int o,int l,int r,int L,int R,int v){ // k in [L,R]
	if(L>R) return;
	f[o][l][r][L]=add(f[o][l][r][L],v),f[o][l][r][R+1]=add(f[o][l][r][R+1],mod-v);
}
int main(){
	int n=read<int>(),m=0;
	for(int i=1;i<=n;++i) m=max(m,read(t[i]));
	int o=0,bound=t[1];
	f[o][0][m+1][1]=1,f[o][0][m+1][bound+1]=mod-1;
	for(int i=2;i<=n;++i){
		for(int l=0;l<=m+1;++l)for(int r=l;r<=m+1;++r)
			for(int k=l;k<=r;++k) f[o][l][r][k]=add(f[o][l][r][k],f[o][l][r][k-1]);
		o^=1,bound=t[i];
		for(int l=0;l<=m+1;++l)for(int r=l;r<=m+1;++r)
			for(int k=l;k<=r;++k) f[o][l][r][k]=0;
		for(int l=0;l<=m+1;++l)for(int r=l;r<=m+1;++r)
			for(int k=l;k<=r;++k)if(f[o^1][l][r][k]){
				int L=max(l,1),R=min(l,bound);
				trans(o,l,l,L,R,f[o^1][l][r][k]);
				L=max(l+1,1),R=min(k-1,bound);
				trans(o,l,k,L,R,f[o^1][l][r][k]);
				if(k>l){
					L=max(k,1),R=min(k,bound);
					trans(o,k,k,L,R,f[o^1][l][r][k]);
				}
				L=max(k+1,1),R=min(r-1,bound);
				trans(o,k,r,L,R,f[o^1][l][r][k]);
				if(r>k){
					L=max(r,1),R=min(r,bound);
					trans(o,r,r,L,R,f[o^1][l][r][k]);
				}
			}
	}
	int ans=0;
	for(int l=0;l<=m+1;++l)for(int r=l;r<=m+1;++r)
		for(int k=l;k<=r;++k){
			f[o][l][r][k]=add(f[o][l][r][k],f[o][l][r][k-1]);
			ans=add(ans,f[o][l][r][k]);
		}
	printf("%d\n",ans);
	return 0;
}

posted on 2020-06-17 08:51  autoint  阅读(130)  评论(0编辑  收藏  举报

导航