[ARC119F] AtCoder Express 3
有简单做法,但是pb大神讲了自动机做法。
这么有趣的自动机不去做?亏大发。
有两个重要的观察。
当你出现长度大于 \(4\) 的连续段时,一定会向后走一次并跳过这一段。
某些时候,当你能用同样的步数数走到最后的两个格子,且其中一个是 \(\rm A\),一个是 \(B\) 时,可以看作你处于一个既能是 \(\rm A\) ,又能是 \(\rm B\) 的格子上。
那么根据这两个性质,我们可以设计 \(13\) 种状态,在上面贪心地转移,最后统计即可。
以 \(\rm O\) 表示一个既能是 \(\rm A\) 又能是 \(\rm B\) 的格子,这 \(13\) 种状态分别是:
- \(\rm O\)
- \(\rm OA\)
- \(\rm OB\)
- \(\rm AB \dots B\)
- \(\rm A\) 前面有 \(\rm B\)
- \(\rm AA\) 前面有 \(\rm B\)
- \(\rm AAA\) 前面有 \(\rm B\)
- \(\rm AB\)
剩下情况是 \(\rm B\) 关于 \(\rm A\) 的对称。
之后就是简单的计数dp,不再赘述。
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int ch[14][2],vc[14][2],nd[14];
int dp[4005][4005][14];
char s[4005];
int n,d;
int main()
{
ch[1][0]=2;vc[1][0]=0;
ch[1][1]=3;vc[1][1]=0;
ch[2][0]=9;vc[2][0]=0;
ch[2][1]=1;vc[2][1]=1;
ch[3][0]=1;vc[3][0]=1;
ch[3][1]=4;vc[3][1]=0;
ch[4][0]=5;vc[4][0]=1;
ch[4][1]=4;vc[4][1]=0;
ch[5][0]=6;vc[5][0]=0;
ch[5][1]=8;vc[5][1]=0;
ch[6][0]=7;vc[6][0]=0;
ch[6][1]=8;vc[6][1]=1;
ch[7][0]=9;vc[7][0]=1;
ch[7][1]=1;vc[7][1]=2;
ch[8][0]=1;vc[8][0]=1;
ch[8][1]=4;vc[8][1]=0;
ch[9][0]=9;vc[9][0]=0;
ch[9][1]=10;vc[9][1]=1;
ch[10][0]=13;vc[10][0]=0;
ch[10][1]=11;vc[10][1]=0;
ch[11][0]=13;vc[11][0]=1;
ch[11][1]=12;vc[11][1]=0;
ch[12][0]=1;vc[12][0]=2;
ch[12][1]=4;vc[12][1]=1;
ch[13][0]=9;vc[13][0]=0;
ch[13][1]=1;vc[13][1]=1;
nd[1]=1;nd[2]=1;nd[3]=1;nd[4]=1;nd[5]=1;nd[6]=2;nd[7]=2;nd[8]=1;nd[9]=1;nd[10]=1;nd[11]=2;nd[12]=2;nd[13]=1;
scanf("%d%d",&n,&d);
scanf("%s",s+1);
dp[0][0][1]=1;
for(int i=0;i<=n-1;i++)
for(int j=0;j<=d;j++)
for(int k=1;k<=13;k++)
if(dp[i][j][k])
{
if(i==n-1)continue;
if(s[i+1]=='A'||s[i+1]=='?')
dp[i+1][j+vc[k][0]][ch[k][0]]=(dp[i+1][j+vc[k][0]][ch[k][0]]+dp[i][j][k])%mod;
if(s[i+1]=='B'||s[i+1]=='?')
dp[i+1][j+vc[k][1]][ch[k][1]]=(dp[i+1][j+vc[k][1]][ch[k][1]]+dp[i][j][k])%mod;
}
int ans=0;
for(int j=0;j<d;j++)
for(int k=1;k<=13;k++)
if(j+nd[k]<=d)ans=(ans+dp[n-1][j][k])%mod;
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号