题解:P14256 平局(draw)
T4 又是神秘计数题,做疑难 dp 时可以先分析子问题将其转化,进而解决大问题。先考虑这个问题:对于一个给定的序列,如何求解最大平局问题?
显然,先将相同的一堆串合并,再接着考虑。我们用
想到这就可以完成前
接下来进一步想正解,我们发现上述过程中有用的信息只有两个:栈里
那么转移就需要一些分类讨论,直接看代码吧。
for(int j=0;j<3;j++) if(s[1]>>j&1) f[1][0][0][j].F=1;
for(int i=2;i<=n;i++) for(int j=0;j<i-1;j++) for(int p=0;p<2;p++) for(int k=0;k<3;k++){
Pa w=f[i-1][j][p][k];
for(int o=0;o<3;o++) if(1<<o&s[i]){
int b=(k-o+4)%3-1;
if(b==0) add(f[i][j][p][o],{w.F,(w.F+w.S)%P});//相同了,这样转移是因为它对每种方案都会贡献1,所以贡献加上方案数*1,下面同理
else if(!j&&!p){//栈空
if(b==1) add(f[i][1][0][o],w);
else add(f[i][0][1][o],w);
}else if(b==1) add(f[i][j+1][p][o],w);//赢了
else{
if(j) add(f[i][j-1][p][o],{w.F,(w.F+w.S)%P});//输和赢拼一个0
else add(f[i][1][0][o],w);//用两个输拼一个赢
}
}
}
for(int i=0;i<n;i++) for(int j=0;j<2;j++) for(int k=0;k<3;k++)
(ans+=(f[n][i][j][k].S+1ll*f[n][i][j][k].F*(i/3)%P)%P)%=P;
这道题其实说明一个想 dp 的方法:先想出一个正确且有前途的求解子问题的方法,观察此过程中记录的变量,将其当状态进行 dp。