您的位置:首页 > 其它

hdu3336kmp,dp

2016-03-24 21:16 267 查看
找出前缀后,算出现次数,很明显的是一个单模式串匹配问题,KMP 可以很好的解决,不过如果直接这样暴力的话,O(n^2) 的复杂度还是不行的。。。因此,我们试着考虑 KMP 算法进行快速匹配的本质核心所在,其实就是 next[] 数组

而这个的本质其实就是 S[1..next[i]]=S[i-next[i]+1…i]

即模式串的最长公共前后缀串的长度

举个例子 ababa

我们要算这个字符串的前缀的出现次数和

a 出现 3

ab 出现 2

aba 出现 2

abab 出现 1

ababa 出现 1

那么我们可以这样来 DP

记 dp[i] 为前 i 个字符组成的前缀出现的次数

则 dp[next[i]]+=dp[i]

这个转移方程是什么含义呢???

我们可以这样来想

如 dp[3] 对应 aba 且 next[5]=3

则 dp[3]+=dp[5] 为答案

因为 S[1..next[i]]=S[i-next[i]+1…i] aba 自己出现了 dp[3] ,然后 S[i-next[i]+1..i] 出现了 dp[5] 也是 aba 会出现的地方,因此也要加上

初始化的时候,记得 dp[i]=1 表示自身匹配算 1 次

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
char s[200005];
int Next[200005];
int dp[200005];
int n;

int getNext()
{
int k=0;
int sum=1;
int len=strlen(s);
Next[0]=0;
dp[0]=1;
for(int i=1;i<len;i++)
{
while(k>0&&s[k]!=s[i])
k=Next[k-1];
if(s[k]==s[i])
k++;
if(k>0)
dp[i]=(dp[k-1]+1)%10007;
else
dp[i]=1;
sum=(sum+dp[i])%10007;
Next[i]=k;
}
return sum;
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%s",&n,s);
printf("%d\n",getNext());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: