题目来源:Light OJ 1334 Genes in DNA
题意:输入文本串和模式串 模式串的前缀和后缀组成(n-1)*(n-1)个组合 求模式串的子串出现多少次前后缀组合 一个子串可以对应多个组合串
思路:既然是前缀和后缀的组合 很好想到正反求2次KMP 枚举相邻的2个字符 i,j 答案就是若干以i结尾的前缀数量乘以j为开始的后缀数量的积的和
求到i字符为止的前缀数量和HDU 3336差不多 有点DP的思想
求以j字符开始的后缀数就是发过来 然后和求前缀一样的
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 50010;
int l[maxn], r[maxn], f[maxn];
int dp1[maxn], dp2[maxn];
char s1[maxn], s2[maxn];
void getFail(char *p, int *dp)
{
int m = strlen(p);
f[0] = f[1] = 0;
dp[0] = 0;
dp[1] = 1;
for(int i = 1; i < m; i++)
{
int j = f[i];
while(j && p[i] != p[j])
j = f[j];
f[i+1] = p[i] == p[j] ? j+1 : 0;
dp[i+1] = p[i] == p[j] ? dp[j+1]+1 : 1;
}
}
void find(char *s1, char* s2, int* dp, int* a)
{
int cnt = 0;
int j = 0;
int n = strlen(s1);
int m = strlen(s2);
for(int i = 0; i < n; i++)
{
while(j && s1[i] != s2[j])
j = f[j];
if(s1[i] == s2[j])
j++;
a[i+1] = dp[j];
if(j == m)
{
a[i+1]--;
j = f[j];
}
}
}
int main()
{
int cas = 1;
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s %s", s1, s2);
int n = strlen(s1);
int m = strlen(s2);
getFail(s2, dp1);
find(s1, s2, dp1, l);
reverse(s1, s1+n);
reverse(s2, s2+m);
getFail(s2, dp2);
find(s1, s2, dp2, r);
long long ans = 0;
for(int i = 1; i < n; i++)
{
ans += (long long)l[i]*r[n-i];
}
printf("Case %d: %lld\n", cas++, ans);
}
return 0;
}