hdu6153 A Secret CCPC网络赛 51nod 1277 KMP
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6153
题意:
给出两个字符串S1,S2,求S2的所有后缀在S1中出现的次数与其长度的乘积之和。
思路:
CCPC网络赛题解: https://post.icpc-camp.org/d/714-ccpc-2017
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1277 是一样的
将s1,s2翻转,转化为求前缀在s1中出现的次数
next数组,记t[i]为长度为i的前缀出现的次数,显然t[n]=1。next[i]即为子串[0,i]的后缀与前缀重复的最长长度,因此可以统计一下next[i]的取值的个数,然后较长的前缀出现一次代表较短的前缀也一次,递推一下即可,复杂度为O(n)。
就是说统计所有在模式串中能匹配上的位置匹配了多少次,再通过fail指针逆推回去,因为长的前缀匹配上了,所有短的前缀也能匹配那么多次。
http://blog.csdn.net/algzjh/article/details/77415529 将S1,S2倒转,用KMP求得S2的fail数组,在S1上滑动的同时,累加结果。 这种是不对的
hack:
KMP好难啊!!! dalao的模板题,我没做出来 菜的一笔
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 1e6+10; const int mod = 1e9+7; char s[maxn],t[maxn]; int l1,l2,f[maxn]; ll ans,cnt[maxn]; void getfail(){ f[0] = f[1] = 0; for(int i=1; i<l2; i++){ int j = f[i]; while(j && s[i]!=s[j]) j=f[j]; f[i+1] = (s[i]==s[j]) ? j+1 : 0; } } int main(){ int T = read(); while(T--){ scanf("%s%s",t,s); l1 = strlen(t), l2 = strlen(s); reverse(t,t+l1); reverse(s,s+l2); getfail(); MS(cnt); int j=0; for(int i=0; i<l1; i++){ while(j && t[i]!=s[j]) j=f[j]; if(t[i] == s[j]) j++; ++cnt[j]; } for(int i=l2; i>=0; i--){ cnt[f[i]] += cnt[i]; cnt[f[i]] %= mod; } ll ans = 0; for(int i=0; i<=l2; i++){ ans = (ans+cnt[i]*i)%mod; } cout << ans << endl; } }
错误代码[数据弱,可以AC]:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const int mod = 1e9 + 7; char str[maxn],tt[maxn]; int nxt[maxn]; ll ans = 0; void getnext(char *t) { int len = strlen(t); nxt[0] = nxt[1] = 0; for (int i = 1; i < len; i++) { int j = nxt[i]; while (j > 0 && t[i] != t[j]) j = nxt[j]; nxt[i+1] = (t[i]==t[j]) ? j+1 : 0; } } void kmp(char *s, char *t) { ll j = 0; ans = 0; int ll = strlen(s); int len = strlen(t); for (int i=0; i<ll; i++) { while (j > 0 && s[i] != t[j]) { ans+=((j*(j+1))/2)%mod; j=nxt[j];} if(s[i] == t[j]) j++; if(j == len) { ans+=((j*(j+1))/2)%mod; j = nxt[j];} if (ans >= mod) ans -= mod; } while(j >= 1){ ans += (j*(j+1))/2; ans %= mod; j = nxt[j]; } } int main() { int T; scanf("%d", &T); while (T--) { ans = 0; scanf("%s%s", str, tt); int l1 = strlen(str); int len = strlen(tt); for (int i = 0, j = len - 1; i <= j; i++, j--) swap(tt[i], tt[j]); for (int i = 0, j = l1 - 1; i <= j; i++, j--) swap(str[i], str[j]); // cout << str << " " << tt << endl; getnext(tt); kmp(str, tt); // for(int i=0; i<=len; i++) // cout << nxt[i] << " "; // puts(""); printf("%I64d\n", ans); } return 0; }