noip模拟35 *糖果

思维量爆炸的一道题,不知道思路是怎么想到的(留坑)....直接讲解法吧
我们先考虑给 \(c\) 序列选数,令 \(dp_{i,j,k}\) 表示 \(a\) 序列处理到第 \(i\) 位,\(b\) 序列处理到第 \(j\) 位,还剩 \(k\)\(c\) 序列的位置不确定选什么数,为了方便递推,我们开两个 \(dp\) 数组分别记录 \(a\) 序列 和 \(b\) 序列的状态方案数。
当我们枚举到一个 \(a\) 的可行方案时,即 \(a_{i}\)\(b\) 中的位置大于 \(j\)
此时我们可以考虑让 \(a\) 序列选他,那此时就可以直接转移到 \(b\) 序列,
另外我们可以考虑让当前数填一个 \(c\) 序列留的坑,
先贴一下代码

if(dp1[i][j][k]) {
	if(i!=n+1) {  // 及转移到最后,如果 c 留的坑为0,则累加方案数。
		if(posb[a[i]]<j) {
			(dp1[i+1][j][k]+=dp1[i][j][k])%=mol; // 不符合情况,a 序列继续向后扫
		}
		else {
			if(k) (dp1[i+1][j][k-1]+=dp1[i][j][k]*k)%=mol; // 添坑,a 序列继续向后扫
					(dp2[i][j][k]+=dp1[i][j][k])%=mol; // a 序列选他,轮到b 序列选数
			}
	} else if(!k) (res+=dp1[i][j][k])%=mol;
}

\(b\) 的情况类似,当枚举到一个合法情况,即 \(b_{j}\)\(a\) 中的位置大于 \(i\)\(a_{i}\) ! = \(b_{j}\)
首先可以考虑让 \(b\) 序列选他,此时转移到 \(i,j,k\) 的下一位。
另外可以考虑添坑,

if(dp2[i][j][k]) {
	if(posa[b[j]]<i) {
		(dp2[i][j+1][k]+=dp2[i][j][k])%=mol; // 不符合情况,b 序列继续向后扫
	}
	else if(a[i]!=b[j]) {
		if(k) (dp2[i][j+1][k-1]+=dp2[i][j][k]*k)%=mol; // 添坑
		(dp1[i+1][j+1][k+1]+=dp2[i][j][k])%=mol; // 转移到下一位,轮a 选数
	}
}

最后一句,我们知道选什么了,其他的地方(2×n/3)还不确定,所以枚举轮数,每次可以用当前选过的数来添两个坑。(解释有点含糊,留坑待补)

for(re int i=1;i<=n3;i++) (res*=(i*3-1)*(i*3-2)%mol)%=mol;  // n3=n/3 
posted @ 2021-08-15 21:45  zJx-Lm  阅读(61)  评论(0编辑  收藏  举报