kkio。|

_kkio

园龄:1年7个月粉丝:6关注:1

[ARC119F] AtCoder Express 3

有简单做法,但是pb大神讲了自动机做法。

这么有趣的自动机不去做?亏大发。

有两个重要的观察。

当你出现长度大于 4 的连续段时,一定会向后走一次并跳过这一段。

某些时候,当你能用同样的步数数走到最后的两个格子,且其中一个是 A,一个是 B 时,可以看作你处于一个既能是 A ,又能是 B 的格子上。

那么根据这两个性质,我们可以设计 13 种状态,在上面贪心地转移,最后统计即可。

O 表示一个既能是 A 又能是 B 的格子,这 13 种状态分别是:

  1. O
  2. OA
  3. OB
  4. ABB
  5. A 前面有 B
  6. AA 前面有 B
  7. AAA 前面有 B
  8. AB

剩下情况是 B 关于 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;
}

本文作者:_kkio

本文链接:https://www.cnblogs.com/hikkio/p/17591831.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _kkio  阅读(24)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起