Another Meaning
题目链接
题目大意
给定一个字符串和模板串,告诉你模板串有2个意思,问这个字符串总共有多少种含义。
题解
DP KMP
这个题我的比标程写的感觉繁琐多了,不过还是说下:
我们设
dpi
为以i结尾串的总含义,对于不匹配的位置,
dpi=dpi−1
,对于匹配的位置,我是分成两部分考虑,如果模式串作为结尾,目前的含义就是前端串含义的值*2,若模式串不作为结尾,考虑模式串的
next
与前端串组成的串,其含义也应该被记入结果,但是如果前端串中间含有模式串,这里会被重复计数,所以利用容斥的思想,把前端串减去就行了。
最近太久不写DP,都没什么感觉了,我这种做法实在繁琐,标称给的很清晰:
对于不匹配的位置: dpi=dpi−1
对于匹配的位置: dpi=dpi−1+dpi−lp (lp为模式串长度)
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 100015
#define LL long long
#define mod 1000000007
using namespace std;
int T,Next[maxn];
char s[maxn],p[maxn];
LL dp[maxn];
void getNext(char s[])
{
int l=strlen(s);
memset(Next,0,sizeof(Next));
for (int i=1;i<l;i++)
{
int k=Next[i-1];
while (k>=0)
{
if (s[k]==s[i]) { Next[i]=k+1; break; }
else
{
if (k==0) break;
k=Next[k-1];
}
}
}
}
int main()
{
int Case=1;
scanf("%d",&T);
while (T--)
{
memset(s,0,sizeof(s));
memset(p,0,sizeof(p));
memset(dp,0,sizeof(dp));
scanf("%s",&s);
scanf("%s",&p);
getNext(p);
int i=0,j=0,ls=strlen(s),lp=strlen(p);
dp[0]=1;
bool flag=0;
while (i<ls)
{
while (s[i]==p[j] && j<lp && i<ls)
{
dp[i+1]=dp[i];
i++; j++;
}
if (j==lp)
{
if (dp[i-lp]==1) dp[i]=(dp[i-lp]*2+dp[i-lp+Next[lp-1]]-1)%mod;
else dp[i]=(dp[i-lp]+dp[i-lp+Next[lp-1]])%mod;
j=Next[lp-1];
}
else if (j==0)
{
dp[i+1]=dp[i];
i++;
}
else j=Next[j-1];
}
printf("Case #%d: %I64d\n",Case++,dp[ls]);
}
return 0;
}