acm-(组合计数、dp计数)2020 China Collegiate Programming Contest Qinhuangdao Site H. Holy Sequence

题面
传送门
首先考虑对于数字 j j j而言,如何计算贡献,假设它有 x x x个,那么 x 2 x^2 x2等价于从整个序列中可以重复地选择两个数字 j j j的选法。而所有 x 2 x^2 x2之和其实就是从所有可能的序列中重复地选择两个数字 j j j的选法之和。

总的来说,两个选法不同,要么两个选法中选择的两个位置存在差异,要么两个选法对应的序列存在差异,这样的话两个选法都会产生一次贡献。

于是对于数字 j j j而言,我们枚举它第一次出现在序列中的位置 i i i,设 p r e [ i ] [ j ] pre[i][j] pre[i][j]表示长度为 i i i的序列,并且 j j j仅仅存在于序列元素最后一个的合法方案数, s u f [ i ] [ j ] suf[i][j] suf[i][j]表示长度为 i i i的序列,并且 j j j作为第一个元素的合法方案数(不考虑 a 0 a_0 a0的限制)。那么对于一个固定的 j , i j,i j,i而言,我们考虑将所有的选法划分为四类:

  1. 两次都选择位置 i i i,方案数为 p r e [ i ] [ j ] ⋅ s u f [ n − i + 1 ] [ j ] pre[i][j]\cdot suf[n-i+1][j] pre[i][j]suf[ni+1][j]
  2. 一次选择位置 i i i,另一次选择位置 k , ( k > i ) k,(k>i) k,(k>i),方案数为 2 ( n − i ) p r e [ i ] [ j ] ⋅ s u f [ n − i ] [ j ] 2(n-i)pre[i][j]\cdot suf[n-i][j] 2(ni)pre[i][j]suf[ni][j](乘二是因为可以第一次选 i i i或第二次选 i i i)
  3. 两次选择位置 k , ( k > i ) k,(k>i) k,(k>i),方案数为 p r e [ i ] [ j ] ⋅ s u f [ n − i ] [ j ] pre[i][j]\cdot suf[n-i][j] pre[i][j]suf[ni][j]
  4. 一次选择位置 k , ( k > i ) k,(k>i) k,(k>i),另一次选择位置 h , ( h > i , h ≠ k ) h,(h>i,h\ne k) h,(h>i,h=k),方案数为 2 C n − i 2 p r e [ i ] [ j ] ⋅ s u f [ n − i − 1 ] [ j ] 2C_{n-i}^2pre[i][j]\cdot suf[n-i-1][j] 2Cni2pre[i][j]suf[ni1][j]

将上述四种情况加起来就是对于一个固定 j j j i i i而言产生的总贡献,枚举 i i i 1 ∼ n 1\sim n 1n就能求出对于数字 j j j而言的总贡献。

下面考虑 p r e [ i ] [ j ] pre[i][j] pre[i][j] s u f [ i ] [ j ] suf[i][j] suf[i][j]如何求解,设 f [ i ] [ j ] f[i][j] f[i][j]表示长度为 i i i的序列最大值为 j j j的合法序列数,那么不难得出 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + f [ i − 1 ] [ j ] ⋅ j f[i][j]=f[i-1][j-1]+f[i-1][j]\cdot j f[i][j]=f[i1][j1]+f[i1][j]j,然后可以发现的是 p r e [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] pre[i][j]=f[i-1][j-1] pre[i][j]=f[i1][j1],于是有 p r e [ i ] [ j ] = p r e [ i − 1 ] [ j − 1 ] + p r e [ i − 1 ] [ j ] ⋅ ( j − 1 ) pre[i][j]=pre[i-1][j-1]+pre[i-1][j]\cdot (j-1) pre[i][j]=pre[i1][j1]+pre[i1][j](j1)

再看 s u f [ i ] [ j ] suf[i][j] suf[i][j],考虑第二个位置上的数与 j j j的大小关系:

  1. 不大于 j j j,此时我们发现第二个位置对后面的位置填什么数字其实没有影响,也就是说我们去掉位置二后,一定存在 s u f [ i − 1 ] [ j ] suf[i-1][j] suf[i1][j]种方案数,加上位置二,并固定位置二上的数字,仍然存在 s u f [ i − 1 ] [ j ] suf[i-1][j] suf[i1][j]种方案,不过由于位置二上可以选择 1 ∼ j 1\sim j 1j,故总方案为 s u f [ i − 1 ] [ j ] ⋅ j suf[i-1][j]\cdot j suf[i1][j]j
  2. 大于 j j j,只可能是 j + 1 j+1 j+1,此时第一个位置对后面位置填什么数字没有影响,可以去掉,方案数即为 s u f [ i − 1 ] [ j + 1 ] suf[i-1][j+1] suf[i1][j+1]

将上面两种情况加起来就能得到: s u f [ i ] [ j ] = s u f [ i − 1 ] [ j + 1 ] + s u f [ i − 1 ] [ j ] ⋅ j suf[i][j]=suf[i-1][j+1]+suf[i-1][j]\cdot j suf[i][j]=suf[i1][j+1]+suf[i1][j]j

int n,pre[maxn][maxn],suf[maxn][maxn];

int main(){
	int t=rd(),kase=0;
	while(t--){
		n=rd(),mod=rd();
		pre[1][1]=1;
		FOR(i,2,n+1)
		FOR(j,2,i+1)pre[i][j]=sum(pre[i-1][j-1],1ll*pre[i-1][j]*(j-1)%mod);
		FOR(i,1,n+1)suf[1][i]=1;
		FOR(i,2,n+1)
		ROF(j,n-1,1)suf[i][j]=sum(suf[i-1][j+1],1ll*suf[i-1][j]*j%mod);
		printf("Case #%d:\n",++kase);
		FOR(j,1,n+1){
			int ans=0;
			FOR(i,j,n+1){
				add(ans,1ll*pre[i][j]*suf[n-i+1][j]%mod);
				add(ans,3ll*pre[i][j]*(n-i)%mod*suf[n-i][j]%mod);
				if(i<n)add(ans,1ll*(n-i)*(n-i-1)%mod*pre[i][j]%mod*suf[n-i-1][j]%mod);
			}
			wr(ans),putchar(' ');
		}
		puts("");
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值