HDU 6153 A Secret ( KMP&&DP || 拓展KMP )
题意 : 给出两个字符串,现在需要求一个和sum,考虑第二个字符串的所有后缀,每个后缀对于这个sum的贡献是这个后缀在第一个字符串出现的次数*后缀的长度,最后输出的答案应当是 sum % 1e9+7
分析 :
有两种做法,如果会拓展KMP的话可以说这就是一道模板题了,拓展KMP专门就是找最长公共前缀的长度,首先将给出的两个字符串双双反转,用模式串去跟主串跑一遍拓展KMP,得到 extend 数组,然后只要遍历一遍 extend 数组,每一个 extend[i] 表示模式串里面前 extend[i] 个前缀都出现过了,因此贡献应该是 1+2+...+extend[i],是等差数列
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
int next[maxn], extend[maxn], moL, strL;
char mo[maxn], S[maxn];
LL sum[maxn];
void GetNext()
{
next[0] = moL;
int a, p;
for (int i = 1, j = -1; i < moL; i++, j--){
if (j < 0 || i + next[i - a] >= p){
if (j < 0) p = i, j = 0;
while (p < moL && mo[p] == mo[j]) p++, j++;
next[i] = j;
a = i;
} else next[i] = next[i - a];
}
}
void GetExtend()
{
GetNext();
int a;
int p;
for (int i = 0, j = -1; i < strL; i++, j--){
if (j < 0 || i + next[i - a] >= p){
if (j < 0) p = i, j = 0;
while (p < strL && j < moL && S[p] == mo[j])
p++, j++;
extend[i] = j;
a = i;
} else extend[i] = next[i - a];
}
}
inline void PrintAns()
{
GetExtend();
LL ans = 0;
for(int i=0; i<strL; i++){
if(extend[i]){
LL tmp = extend[i];
tmp = (tmp+1)*tmp/2;
ans = (ans%mod + tmp%mod)%mod;
}
}
printf("%lld\n", ans);
}
int main()
{
int nCase;
scanf("%d", &nCase);
while(nCase--){
scanf("%s %s", S, mo);
strL = strlen(S);
moL = strlen(mo);
std::reverse(S, S+strL);
std::reverse(mo, mo+moL);
PrintAns();
}
return 0;
}
而KMP做法就是用到了NEXT数组的性质,在解决这题之前or后可以看看这道非常相似的题 ==> 51Nod 1277
只要理解了51Nod 1277的kmp+dp解法,这道题直接效仿即可,关于 51Nod 1277 的题解报告点这里 or 百度
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
int Next[maxn], moL, strL;
long long d[maxn];
char mo[maxn], str[maxn];
inline void GetNext()
{
int i = 0, j = -1;
Next[i] = j;
while(i < moL){
while(j!=-1 && mo[j]!=mo[i]) j = Next[j];
Next[++i] = ++j;
}
}
inline void Kmp()
{
memset(d, 0, sizeof(d));
int i = 0, j = 0;
while(i < strL){
while(j!=-1 && mo[j]!=str[i]) j = Next[j];
i++, j++, d[j]++;
if(j == moL) j = Next[j];
}
}
inline void PrintAns()
{
GetNext(); Kmp();
long long sum = 0;
for(int i=moL; i>0; i--){
d[Next[i]] += d[i];
sum = (sum + d[i]*i) % mod;
}
printf("%I64d\n", sum);
}
int main(void)
{
int nCase;
scanf("%d", &nCase);
while(nCase--){
scanf("%s %s", str, mo);
moL = strlen(mo);
strL = strlen(str);
std::reverse(str, str+strL);
std::reverse(mo , mo+moL);
PrintAns();
}
return 0;
}