题目来源:Light OJ 1334 Genes in DNA
题意:输入文本串和模式串 模式串的前缀和后缀组成(n-1)*(n-1)个组合 求模式串的子串出现多少次前后缀组合 一个子串可以对应多个组合串
思路:既然是前缀和后缀的组合 很好想到正反求2次KMP 枚举相邻的2个字符 i,j 答案就是若干以i结尾的前缀数量乘以j为开始的后缀数量的积的和
求到i字符为止的前缀数量和HDU 3336差不多 有点DP的思想
求以j字符开始的后缀数就是发过来 然后和求前缀一样的
#include
#include
#include
#include
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; }