hdu 5763 Another Meaning (KMP/哈希+DP)

题目大意:给你两个串,一长一短,如果长串中某个子串和短串完全相同,则这个子串可以被替换成"#",求长串所有的表达形式.......

比如"hehehehe"和"hehe",则有5种情况,"#hehe","he#he","hehe#","##","hehehehe"

首先我们KMP/哈希找出长串中所有可以作为和短串结尾匹配成功后的位置

然后可以得到方程

f[i]=f[i-1]                         (不是子串结尾)

f[i]=f[i-1]+f[i-len]  (是子串结尾)

至于原因呢,如果它不是子串结尾,那么它不能被替换,所以是f[i-1]

而如果它是子串结尾,它既可以不被替换,即f[i-1]

也可以被替换,那么替换整个短串,转移的地方就是f[i-len]

然后转移一下即可,建议从1开始读入字符串方便转移

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100100
#define mod 1000000007
#define ui unsigned int
#define ll long long
using namespace std;

int T,ls,lt;
int ed[N],nxt[N];
ui f[N];
char s[N],t[N];
void get_kmp()
{
    int i=1,j=0;
    nxt[1]=0;
    while(i<=lt)
    {
        if(j==0||t[i]==t[j])
        {
            i++;
            j++;
            nxt[i]=j;
        }else{
            j=nxt[j];
        }
    }
}
void KMP()
{
    int i=1,j=1;
    while(i<=ls)
    {
        if(j==0||s[i]==t[j])
        {
            i++;
            j++;
        }else{
            j=nxt[j];
        }
        if(j==lt+1)
        {
            ed[i-1]=1;
            j=nxt[j];
        }
    }
}
ui solve()
{
    f[0]=1;
    for(int i=1;i<=ls;i++)
    {
        if(ed[i]==1)
        {
            f[i]=(f[i-lt]+f[i-1])%mod;
        }else{
            f[i]=f[i-1];
        }
    }
    return f[ls];
}

int main()
{
    //freopen("aa.in","r",stdin);
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        memset(nxt,0,sizeof(nxt));
        memset(ed,0,sizeof(ed));
        memset(f,0,sizeof(f));
        scanf("%s",s+1),ls=strlen(s+1);
        scanf("%s",t+1),lt=strlen(t+1);
        get_kmp();
        KMP();
        printf("Case #%d: %u\n",i,solve());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/guapisolo/article/details/81709291