链接:http://acm.hdu.edu.cn/showproblem.php?pid=5763
题意:给出字符串a,b,其中,字符串b代表两种含义,问a最多有多少种含义。
题解:kmp找出b在a中对应的位置,根据位置关系dp
令dp[i]表示到i结尾的字符串可以表示的不同含义数,那么考虑两种转移:
末尾不替换含义:dp[i - 1]
末尾替换含义:dp[i - |B|] (A.substr(i - |B| + 1,|B|) = B)
那么对于末尾替换含义的转移,需要快速判断B能不能和当前位置的后缀匹配,kmp或者hash判断即可。
复杂度:O(N)
code:
#include <bits/stdc++.h>
using namespace std;
int Scan()
{
int res=0,ch,flag=0;
if((ch=getchar())=='-')flag=1;
else if(ch>='0'&&ch<='9')res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
return flag?-res:res;
}
void Out(int a)
{
if(a>9)Out(a/10);
putchar(a%10+'0');
}
#define bug cout<<"bug"<<endl
#define INF 0x3f3f3f3f
#define mod 1000000007
const int maxn = 1e5+7;
char str[maxn];
char poi[maxn];
int Next[maxn];
int temp[maxn];
int lena, lenb;
void get_next(char *s)
{
int i=0,j=-1;
lenb=strlen(s);
Next[0]=-1;
while(i<lenb)
{
if(j==-1 || s[i]==s[j])
Next[++i]=++j;
else j=Next[j];
}
}
void kmp()
{
int i=0,j=0;
lena=strlen(str);
while(i<lena)
{
if(j==-1||str[i]==poi[j])
++i,++j;
else j=Next[j];
if(j==lenb)
{
temp[i-1]=1;
j=Next[j];
}
}
}
long long ans[maxn];
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
memset(temp,0,sizeof(temp));
memset(ans,0,sizeof(ans));
scanf("%s",str);
scanf("%s",poi);
get_next(poi);
kmp();
ans[0]=1;
for(int i=0; i<lena; ++i)
{
if(!temp[i])ans[i+1]=ans[i];
else ans[i+1]=(ans[i]+ans[i-lenb+1])%mod;
}
printf("Case #%d: %I64d\n",cas++,ans[lena]);
}
}
/*
4
hehehe
hehe
woquxizaolehehe
woquxizaole
hehehehe
hehe
owoadiuhzgneninougur
iehiehieh
*/