track

这里写图片描述
这里写图片描述
这里写图片描述
____________________________________________________
dp大法好啊,然而我打错了。。。
还是先抽象题目,我们可以神奇看成是Jerry的跑动方式构成一个字符串(任意前缀D不可以大于U,且整个字符串最终D和U个数相同),如果有一个满足Tom的子序列则判断为合法,求合法序列。、

貌似有点太抽象了,各位大概感觉一下就可以了。。。

原版错误决策是这样的(,雾):定义f[i][j][k]为当Tom跑了i秒、当前高度为j、且有k位与摔倒序列匹配(相同)。比如摔倒序列要求Tom下一步向下跑,则有

f[i+1][j+1][0]+=f[i][j][k],
f[i][j-1][k+1]+=f[i][j][k];

没有仔细考虑所以莫名其妙骗到了10分?

发现问题已经很明显了有没有?我们每次判断跑错步时并不需要直接回到0,这有一点像字符串中的失配,回到零会使方案数大大减少。其实我们可以像kmp算法时一样进行一个回溯,找到一个最长前缀并要求下一位和失配操作相同。可以用fail[i][0/1]表示长度为i的字符串回溯后下一步为0/1的最长前缀,其实是nxt的精简版。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
const int maxn=202;
int n,f[maxn][maxn][maxn];
char s[maxn];
int len;int fail[maxn][2],nxt[maxn];
void getfail(){
    int j=0;
    nxt[0]=nxt[1]=0;
    for(int i=1;i<len;i++){
        while(j>0&&s[i]!=s[j])j=nxt[j];
        if(s[i]==s[j]) j++;
        nxt[i+1]=j;
    }//基本kmp

    fail[0][s[0]=='U']=1;
    for(int i=1;i<=len;i++){
        int pos=i;
        while(pos&&s[pos]!='U') pos=nxt[pos];
        fail[i][1]=pos+1;
        if(pos==0&&s[0]=='D')fail[i][1]=0;

        pos = i;
        while(pos && s[pos] != 'D') pos = nxt[pos];
        fail[i][0] = pos + 1;
        if(pos == 0 && s[0] == 'U') fail[i][0] = 0;
    }
    return;
}
int main(){
    cin>>n;
    scanf("%s",s);
    len=strlen(s);
    if(n&1) {
        printf("0\n");
        return 0;
    }
    getfail();
    f[0][0][0]=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<=min(i,n-i);j++){
            for(int k=0;k<len;k++){
                if(s[k]=='U'){
                    f[i+1][j+1][k+1]=(f[i+1][j+1][k+1]+f[i][j][k])%mod;
                    if(j)(f[i+1][j-1][fail[k][0]]+=f[i][j][k])%=mod;
                }
                else{
                    (f[i+1][j+1][fail[k][1]]+=f[i][j][k])%=mod;
                    if(j)(f[i+1][j-1][k+1]+=f[i][j][k])%=mod;
                }
            }
            (f[i+1][j+1][len]+=f[i][j][len])%=mod;
            if(j)(f[i+1][j-1][len]+=f[i][j][len])%=mod;
        }
    }
    cout<<f[n][0][len]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/81670269