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