首先是几份模版
KMP
void kmp_pre(char x[],int m,int fail[]) { int i,j; j = fail[0] = -1; i = 0; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int kmp_count(char x[],int m,char y[],int n) { int i = 0,j = 0; int ans = 0; while (i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; i++;j++; if (j >= m) { ans++; j = fail[j]; } } return ans; }
最小表示法 。资料http://blog.csdn.net/acm_cxlove/article/details/7909087
HDU 3374 String problem
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; char str[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int getval(char * str,int len,bool type) { int i = 0,j = 1,k = 0; while (i < len && j < len && k < len) { int val = str[(j + k) % len] - str[(i + k) % len]; if (val == 0) k++; else { if (type) { if (val > 0) j += k + 1; else i += k + 1; } else { if (val > 0) i += k + 1; else j += k + 1; } k = 0; if (i == j) j++; } } return min(i,j); } int main() { while (scanf("%s",str) != EOF) { int len = strlen(str); kmp_pre(str,len,fail); int l = getval(str,len,true); int r = getval(str,len,false); int ret = len % (len - fail[len]) ? 1 : len / (len - fail[len]); printf("%d %d %d %d ",l + 1,ret,r + 1,ret); } return 0; }
扩展KMP 学习资料http://wenku.baidu.com/link?url=oRb889beOwu3N4gZHJ0W3o91I78GpCqjIGdOmfPIp3WD5GxCHdc3njCXu0ocgDKTSNaBG_deOWszmrVFZMrbTiureG3otYc522XrJcqdbry
模版1:
HDU 3613 BestReward
将一个串分成2段,如果一段不是回文串,那么权值为0,否则为按照对应法则的权值
权值不是很难统计直接前缀和
这里用扩展KMP来判断回文串,将原串反转得到T,那么由扩展KMP的定义,
判断前半段串如果是回文串的时候,就是以原串为模式传,反串为回文串,判断EXTEND[i] + i == len
后半段同理直接暴力

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 500010; const int INF = 0x3f3f3f3f; char S[MAXN],T[MAXN]; int fail[MAXN]; int ext1[MAXN],ext2[MAXN]; int val[30]; int sum[MAXN]; void pre_ekmp(char x[],int m,int fail[]) { fail[0] = m; int j = 0; while (j + 1 < m && x[j] == x[j + 1]) j++; fail[1] = j; int k = 1; for (int i = 2 ; i < m ; i++) { int p = fail[k] + k - 1; int L = fail[i - k]; if (i + L < p + 1) fail[i] = L; else { j = max(0,p - i + 1); while (i + j < m && x[i + j] == x[j]) j++; fail[i] = j; k = i; } } } void ekmp(char x[],int m,char y[],int n,int fail[],int extend[]) { pre_ekmp(x,m,fail); int j = 0; while (j < n && j < m && x[j] == y[j])j++; extend[0] = j; int k = 0; for (int i = 1 ; i < n ; i++) { int p = extend[k] + k - 1; int L = fail[i - k]; if (i + L < p + 1) extend[i] = L; else { j = max(0,p - i + 1); while (i + j < n && j < m && y[i + j] == x[j]) j++; extend[i] = j; k = i; } } } int main() { int kase; scanf("%d",&kase); while (kase--) { for (int i = 0 ; i < 26 ; i++) scanf("%d",&val[i]); scanf("%s",S); memset(sum,0,sizeof(sum)); int len = strlen(S); for (int i = 0 ; i < len ; i++) sum[i + 1] = sum[i] + val[S[i] - 'a']; for (int j = len - 1,i = 0 ; j >= 0 ;j--,i++) T[i] = S[j]; T[len] = ''; // printf("%s %s ",S,T); ekmp(S,len,T,len,fail,ext1); ekmp(T,len,S,len,fail,ext2); // for (int i = 0 ; i <= len ; i++) printf("%d ",ext1[i]); puts(""); //for (int i = 0 ; i <= len ; i++) printf("%d ",ext2[i]); puts(""); //for (int i = 0 ; i <= len ; i++) printf("%d ",sum[i]); puts(""); int ret = 0; for (int i = 0 ; i < len ; i++) { if (i > 0 && ext1[i] + i == len) { int pos = ext1[i]; int res = sum[pos]; // printf("%d %d ",i,res); if (ext2[pos] + pos == len) { res += sum[len] - sum[pos]; } // printf("%d %d ",i,res); ret = max(res,ret); } else { int pos = i + 1; int res = 0; if (ext2[pos] + pos == len) res += sum[len] - sum[pos]; ret = max(ret,res); } } printf("%d ",ret); } return 0; }
模版2 拼接多串的扩展KMP
POJ 3376 Finding Palindromes
求串串之间的组合方案中,有多少个回文串。
贴一下别人的题解
题意:给你n个字符串m1、m2、m3...mn 求S = mimj(1=<i,j<=n)是回文串的数量
思路:我们考虑第i个字符串和第j个字符串能构成组合回文串要满足的条件:
1、i的长度小于j,那么i一定是j的反串的前缀,且j的反串剩下的后缀是回文串
2、i的长度等于j,那么i等于j的反串
3、i的长度大于j,那么j的反串一定是i的前缀,且i串剩下的后缀是回文串
我们可以将这n个字符串插入trie,每个节点要维护两个值:value1. 到当前节点的字符串个数;value2. 当前节点后面的回文子串个数
我们用每个字符串的反串去trie上查找,要构成回文串有以下情况:
1、 此反串是其他串的前缀,那么组合回文串的数量就要加上value2
2、此反串的前缀是某些字符串,且反串剩下的后缀是回文串,那么组合回文串的数量要加上value1
3、2的特例:此反串的前缀是某些字符串,且反串剩下的后缀为空,同样要加上value1,这种情况可以和2一起处理
关键:
1、判断字符串的哪些后缀是回文串(用于更新value2),以及对应反串的哪些后缀是回文串(当面临第二种情况时,可直接判断后缀否为回文串)
2、如何更新value1和value2(借助1的结果)
很好的题目。反正我看着这份题解搞的

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 2000010; const int MAXD = 26; struct node { int num; int tot; node * nxt[MAXD]; }src[MAXN]; node * root; int st[MAXN],ed[MAXN]; bool flag[2][MAXN]; char S[MAXN],T[MAXN]; int extend[MAXN]; LL ret; int cas; int fail[MAXN]; void pre_ekmp(char x[],int lft,int rht) { int j = 0; while (lft + 1 + j <= rht && x[lft + j] == x[lft + j + 1]) j++; fail[lft + 1] = j; int k = lft + 1; for (int i = lft + 2 ; i <= rht ; i++) { int p = fail[k] + k - 1; int L = fail[lft + i - k]; if (L + i < p + 1) fail[i] = L; else { j = max(0,p - i + 1); while (i + j <= rht && x[lft + j] == x[i + j]) j++; fail[i] = j; k = i; } } } void ekmp(char S[],char T[],int lft,int rht,bool type) { pre_ekmp(T,lft,rht); int j = 0; while (j + lft <= rht && S[j + lft] == T[lft + j])j++; extend[lft] = j; int k = lft; for (int i = lft + 1; i <= rht ; i++) { int p = extend[k] + k - 1; int L = fail[lft + i - k]; if (L + i < p + 1) extend[i] = L; else { j = max(0,p - i + 1); while (i + j <= rht && S[i + j] == T[lft + j])j++; extend[i] = j; k = i; } } for (int i = lft ; i <= rht ; i++) { if (extend[i] + i == rht + 1) flag[type][i] = true; } } void Insert(char str[],int lft,int rht) { node * u = root; for (int i = lft ; i <= rht ; i++) { int ch = str[i] - 'a'; u -> tot += flag[0][i]; if (u -> nxt[ch] == NULL) { u -> nxt[ch] = &src[cas++]; } u = u -> nxt[ch]; } u -> num++; } void Find(char *str,int lft,int rht) { node * u = root; for (int i = lft ; i <= rht ; i++) { int ch = str[i] - 'a'; u = u -> nxt[ch]; if (u == NULL) break; if ((i < rht && flag[1][i + 1]) || i == rht) ret += u -> num; } if (u != NULL) ret += u -> tot; } int main() { int N; while (scanf("%d",&N) != EOF) { ret = 0; cas = 0; memset(src,0,sizeof(src)); memset(flag,false,sizeof(flag)); root = &src[cas++]; int length = 0; for (int i = 0 ; i < N ; i++) { int d; scanf("%d%s",&d,S + length); for (int j = 0 ; j < d ; j++) T[length + j] = S[length + d - 1 - j]; st[i] = length; ed[i] = length + d - 1; ekmp(S,T,st[i],ed[i],false); ekmp(T,S,st[i],ed[i],true); Insert(S,st[i],ed[i]); length += d; } for (int i = 0 ; i < N ; i++) Find(T,st[i],ed[i]); printf("%I64d ",ret); } return 0; }
Manacher
POJ 3974 Palindrome

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; char ma[MAXN * 2]; int mp[MAXN * 2]; void Manacher(char str[],int len) { int l = 0; ma[l++] = '$'; ma[l++] = '#'; for (int i = 0 ; i < len ; i++) { ma[l++] = str[i]; ma[l++] = '#'; } ma[l] = 0; int mx = 0,id = 0; for (int i = 0 ; i < l ; i++) { mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1; while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++; if (i + mp[i] > mx) { mx = i + mp[i]; id = i; } } int ret = 0; for (int i = 0 ; i < l ; i++) ret = max(ret,mp[i] - 1); printf("%d ",ret); } char str[MAXN]; int main() { int kase = 1; while (scanf("%s",str) != EOF) { if (strcmp(str,"END") == 0) break; printf("Case %d: ",kase++); Manacher(str,strlen(str)); } return 0; }
HDU 4513 吉哥系列故事――完美队形II
要求回文串是山峰式的,中间大。带点要求的回文串,相应修改马拉车代码

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 100010; int ma[MAXN * 2]; int mp[MAXN * 2]; int src[MAXN],N; void manacher(int str[],int len) { int l = 0; ma[l++] = '$'; ma[l++] = '#'; for (int i = 0 ; i < len ; i++) { ma[l++] = str[i]; ma[l++] = '#'; } ma[l] = 0; int mx = 0,id = 0; for (int i = 0 ; i < l ; i++) { mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1; while(ma[i + mp[i]] == ma[i - mp[i]] && ma[i - mp[i]] <= ma[i - mp[i] + 2]) mp[i]++; if(i + mp[i] > mx) { mx = i + mp[i]; id = i; } } //for (int i = 0 ; i < l ; i++) printf("%d ",ma[i]); puts(""); //for (int i = 0 ; i < l ; i++) printf("%d ",mp[i]); puts(""); int ret = 0; for (int i = 0 ; i < l ; i++) ret = max(ret,mp[i] - 1); printf("%d ",ret); } int main() { int T; scanf("%d",&T); while (T--) { scanf("%d",&N); for (int i = 0 ; i < N ; i++) scanf("%d",&src[i]); manacher(src,N); } return 0; }
HDU 3294 girl's reseach
这个题目设计到答案输出。注意添加字符#是对偶数回文串有影响的

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 200010; char ma[MAXN * 2]; int mp[MAXN * 2]; int idx[MAXN * 2]; char str[MAXN]; map<char,char>res; void Manacher(char str[],int len) { memset(idx,-1,sizeof(idx)); int l = 0; ma[l++] = '$'; ma[l++] = '#'; for (int i = 0 ; i < len ; i++) { idx[l] = i; ma[l++] = str[i]; idx[l] = i; ma[l++] = '#'; } ma[l] = 0; int mx = 0,id = 0; for (int i = 0 ; i < l ; i++) { mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1; while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++; if (i + mp[i] > mx) { mx = i + mp[i]; id = i; } } int ret = 0,post; for (int i = 0 ; i < l ; i++) { if (str[i] != '#' && str[i] != '$' && mp[i] - 1 > ret) { ret = mp[i] - 1; post = i; } } if (ret == 1) puts("No solution!"); else { if (ret % 2) { printf("%d %d ",idx[post] - (ret - 1) / 2,idx[post] + (ret - 1) / 2); for (int j = idx[post] - (ret - 1) / 2 ; j <= idx[post] + (ret - 1) / 2 ; j++) printf("%c",str[j]); puts(""); } else { printf("%d %d ",idx[post] - ret / 2 + 1,idx[post] + ret / 2); for (int j = idx[post] - ret / 2 + 1 ; j <= idx[post] + ret / 2; j++) printf("%c",str[j]); puts(""); } } } int main() { char op[5]; while (scanf("%s%s",op,str) != EOF) { res.clear(); int pos = op[0] - 'a'; for (int i = 0 ,j = pos ; i < 26 ; i++,j = (j + 1) % 26) res[j + 'a'] = i + 'a'; int len = strlen(str); for (int i = 0 ; i < len ; i++) { str[i] = res[str[i]]; } Manacher(str,len); } return 0; }
HDU 1711 Number Sequence
找到最早匹配的位置模版题

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; const int MAXD = 10010; int src[MAXN],tag[MAXD]; int N,M; int fail[MAXD]; void kmp_pre(int x[],int m,int fail[]) { int i,j; j = fail[0] = -1; i = 0; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int kmp_count(int x[],int m,int y[],int n) { int i,j; int ans = 0; i = j = 0; while (i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; i++;j++; if (j >= m) { return i - m; ans++; j = fail[j]; } } return -1; } int main() { int T; scanf("%d",&T); while (T--) { scanf("%d%d",&N,&M); for (int i = 0 ; i < N ; i++) scanf("%d",&src[i]); for (int i = 0 ; i < M ; i++) scanf("%d",&tag[i]); kmp_pre(tag,M,fail); int ret = kmp_count(tag,M,src,N); printf("%d ",ret == -1 ? -1 : ret + 1); } return 0; }
HDU 1686 Oulipo
可重叠子串出现次数

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; const int MAXD = 10010; char src[MAXN],tag[MAXD]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i,j; j = fail[0] = -1; i = 0; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int kmp_count(char x[],int m,char y[],int n) { int i = 0,j = 0; int ans = 0; while (i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; i++;j++; if (j >= m) { ans++; j = fail[j]; } } return ans; } int main() { int T; scanf("%d",&T); while (T--) { scanf("%s%s",tag,src); int lenn = strlen(src); int lenm = strlen(tag); kmp_pre(tag,lenm,fail); int ret = kmp_count(tag,lenm,src,lenn); printf("%d ",ret); } return 0; }
HDU 2087 剪花布条
不可重叠子串的次数。记录匹配位置扫一遍即可

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 10010; char src[MAXN],tag[MAXN]; int fail[MAXN]; int tot,pos[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } void kmp_count(char x[],int m,char y[],int n) { int i = 0 , j = 0; int ans = 0; while (i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; ++i; ++j; if (j >= m) { pos[tot++] = i - m; j = fail[j]; ans++; } } } int main() { while (scanf("%s",src) != EOF) { if (src[0] == '#') break; scanf("%s",tag); int m = strlen(tag); kmp_pre(tag,m,fail); int n = strlen(src); tot = 0; kmp_count(tag,m,src,n); if (tot == 0) { puts("0"); continue; } int ret = 1,pre = 0; for (int i = 1 ; i < tot ; i++) { if (pos[i] - pos[pre] >= m) { ret++; pre = i; } } printf("%d ",ret); } return 0; }
HDU 3746 Cyclic Nacklace
最少添加多少个字符使得字符串存在循环节,循环次数要大于等于2
循环接长度为len-fail[len]计算答案即可

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 100010; char src[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int main() { int T; scanf("%d",&T); while (T--) { scanf("%s",src); int len = strlen(src); kmp_pre(src,len,fail); if (fail[len] != 0 && len % (len - fail[len]) == 0) { puts("0"); continue; } else { printf("%d ",(len - fail[len]) - fail[len] % (len - fail[len])); } } return 0; }
HDU 1358 Period
依然求循环节

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; char str[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0 ,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int main() { int kase = 1; int m; while (scanf("%d",&m) != EOF) { if (m == 0) break; printf("Test case #%d ",kase++); scanf("%s",str); kmp_pre(str,m,fail); for (int i = 2 ; i <= m ; i++) { if (i % (i - fail[i]) == 0) { if (i / (i - fail[i]) > 1) printf("%d %d ",i,i / (i - fail[i])); } } puts(""); } return 0; }
hust 1010 The Minimum Length
某个串A复制无数次后变成串B,从B中截取一段子串C,给出C求最短的A
注意到串一定是循环的。不要想复杂了 ,就是说我求出来循环节。后边也一定是循环的。 不用考虑去判断他。
所以直接求C的循环接即可

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; char str[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int main() { while (scanf("%s",str) != EOF) { int len = strlen(str); kmp_pre(str,len,fail); printf("%d ",len - fail[len]); } return 0; }
POJ 2406 循环节
POJ 2752 Seek the Name, Seek the Fame
求所有是前缀同时也是后缀的字串
由NEXT定义直接递推的找next值即可

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 400010; char str[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int tot; int ret[MAXN]; int main() { while (scanf("%s",str) != EOF) { int len = strlen(str); kmp_pre(str,len,fail); tot = 0; int cur = len; ret[tot++] = len; while (fail[cur] > 0) { ret[tot++] = fail[cur]; cur = fail[cur]; } sort(ret,ret + tot); for (int i = 0 ; i < tot ; i++)printf("%d ",ret[i]);puts(""); } return 0; }
POJ 3080 Blue Jeans
直接暴力

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000; char str[MAXN],src[MAXN]; int fail[MAXN]; struct node { char word[80]; int length; friend bool operator < (const node &a,const node &b) { return a.length < b.length; } }res[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i,j; j = fail[0] = -1; i = 0; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } bool kmp_find(char x[],int m,char y[],int n) { int i,j; i = j = 0; while(i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; i++; j++; if (j >= m) return true; } return false; } int main() { //freopen("sample.txt","r",stdin); int T; scanf("%d",&T); while (T--) { int N; scanf("%d",&N); for (int i = 0 ; i < N ; i++) { scanf("%s",res[i].word); res[i].length = strlen(res[i].word); } sort(res,res + N); char tmp[110],cmp[110]; int ret = 0; for (int l = 0 ; l < res[0].length ; l++) { for (int r = l ; r < res[0].length ; r++) { int leap = 0; for (int i = l ; i <= r ; i++) tmp[leap++] = res[0].word[i]; tmp[leap] = ''; bool flag = false; kmp_pre(tmp,leap,fail); for (int i = 1 ; i < N ; i++) { if (!kmp_find(tmp,leap,res[i].word,res[i].length)) { flag = true; break; } } if (!flag) { if (r - l + 1 > ret) { ret = r - l + 1; int step = 0; for (int i = l ; i <= r ; i++) cmp[step++] = res[0].word[i]; cmp[step] = ''; } else if (r - l + 1 == ret) { if (strcmp(tmp,cmp) < 0) strcpy(cmp,tmp); } } } } if (ret < 3) printf("no significant commonalities "); else { printf("%s ",cmp); } } return 0; }
HDU 2594 Simpsons’ Hidden Talents
是A串前缀B串后缀的最长串
拼串求NEXT注意坑点最长串小于等于min(|A|,|B|);

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 100010; char str[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int main() { while (scanf("%s",str) != EOF) { int len = strlen(str); int res = len; scanf("%s",str + len); len = strlen(str); kmp_pre(str,len,fail); int tmp = len - res; if (fail[len] == 0) { puts("0"); continue; } for (int i = 0 ; i < min(res,min(tmp,fail[len])) ; i++) printf("%c",str[i]); putchar(' '); printf("%d ",min(res,min(tmp,fail[len]))); } return 0; }
hdu 3336 Count the string
根据next数组递推

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 200010; const int MOD = 10007; char str[MAXN]; int fail[MAXN],num[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int main() { int T,kase = 1; scanf("%d",&T); while (T--) { int N; scanf("%d",&N); scanf("%s",str); kmp_pre(str,N,fail); memset(num,0,sizeof(num)); for (int i = 1 ; i <= N ; i++) num[fail[i]] = (num[fail[i]] + 1) % MOD; int sum = 0; for (int i = 1 ; i <= N ; i++) { if (num[i] == 0) sum = (sum + 1) % MOD; else sum = (sum + num[i] + 1) % MOD; } printf("%d ",sum); } return 0; }
HDU 4300 Clairewd’s message

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 100010; int fail[MAXN]; char trans[30],str[MAXN]; int pos[MAXN]; char tag[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int kmp_count(char x[],int m,char y[]) { int i = 0 , j = 0; int n = strlen(y); while (i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; i++; j++; if (j >= m) { j = fail[j]; } } return j; } int main() { int T; scanf("%d",&T); while (T--) { scanf("%s",trans); scanf("%s",str); int len = strlen(str); for (int i = 0 ; i < 26 ; i++) pos[trans[i] - 'a'] = i; for (int i = 0 ; i < len ; i++) tag[i] = pos[str[i] - 'a'] + 'a'; tag[len] = ''; kmp_pre(tag,len,fail); int ret = kmp_count(tag,len,str + (len + 1) / 2); for (int i = 0 ; i < len - ret ; i++) printf("%c",str[i]); for (int i = 0 ; i < len - ret ; i++) printf("%c",tag[i]); puts("");; } return 0; }
HDU 1238 直接暴力

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 210; int pos,N; int fail[MAXN]; char src[MAXN],tag[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } bool kmp_count(char x[],int m,char y[],int n) { int i = 0 ,j = 0; kmp_pre(x,m,fail); while (i < n) { while (j != -1 && y[i] != x[j]) j = fail[j]; i++; j++; if (j >= m) return true; } return false; } char input[MAXN][MAXN]; int length[MAXN]; bool can(char *str) { int leng = strlen(str); for (int i = 0 ; i < N ; i++) { if (i == pos) continue; if (!kmp_count(str,leng,input[i],length[i] * 2)) return false; } return true; } bool judge(int mid) { for (int i = 0 ; i + mid <= length[pos]; i++) { char tmp[MAXN]; int cas = 0; for (int j = i ; j <= i + mid - 1 ; j++) tmp[cas++] = input[pos][j]; tmp[cas] = ''; if (can(tmp)) return true; } return false; } void dealinput() { scanf("%d",&N); pos = 0; for (int i = 0 ; i < N ; i++) { scanf("%s",input[i]); length[i] = strlen(input[i]); if (length[i] < length[pos]) pos = i; for (int j = length[i] - 1 ,k = length[i]; j >= 0 ; j--,k++) input[i][k] = input[i][j]; input[i][length[i] * 2] = ''; } // for (int i = 0 ; i < N ; i++) // printf("%s %d ",input[i],length[i]); } int main() { int T; scanf("%d",&T); while (T--) { dealinput(); int L = 0,R = 100; int ans = 0; while (L <= R) { int mid = (L + R) / 2; if (judge(mid)) { ans = mid; L = mid + 1; } else R = mid - 1; } printf("%d ",ans); } return 0; }
HDU 2328 Corporate Identity
后缀数组又来了一次

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 900100; const int INF = 0x3f3f3f3f; int sa[MAXN],r[MAXN]; int t1[MAXN],t2[MAXN],c[MAXN]; int Rank[MAXN],height[MAXN]; void build_sa(int s[],int n,int m) { int i,j,p,*x = t1,*y = t2; for(i = 0 ; i < m ; i++) c[i] = 0; for(i = 0 ; i < n ; i++) c[x[i] = s[i]]++; for(i = 1 ; i < m ; i++) c[i] += c[i - 1]; for(i = n - 1 ; i >= 0 ; i--) sa[--c[x[i]]] = i; for(j = 1 ; j <= n ; j <<= 1) { p=0; for(i = n - j ; i < n ; i++) y[p++] = i; for(i = 0 ; i < n ; i++) if(sa[i] >= j) y[p++] = sa[i] - j; for(i = 0 ; i < m ; i++) c[i] = 0; for(i = 0 ; i < n ; i++) c[x[y[i]]]++; for(i = 1 ; i < m ; i++) c[i]+=c[i-1]; for(i = n - 1 ; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sa[0]] = 0; for(i = 1 ; i < n ; i++) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++; if(p >= n)break; m = p; } } void getHeight(int s[],int n) { int i,j,k = 0; for(i = 0;i <= n ; i++) Rank[sa[i]] = i; for(i = 0;i < n ; i++) { if(k)k--; j = sa[Rank[i] - 1]; while(s[i + k] == s[j + k])k++; height[Rank[i]] = k; } } /* int mm[MAXN]; int best[20][MAXN]; void initRMQ(int n) { mm[0] = -1; for(int i = 1 ; i <= n ;i++) mm[i] = ((i & (i - 1)) == 0)?mm[i - 1] + 1:mm[i - 1]; for(int i = 1 ; i <=n ; i++) best[0][i] = i; for(int i = 1 ; i <=mm[n] ; i++) for(int j = 1 ; j + (1 << i) - 1 <= n ; j++) { int a=best[i - 1][j]; int b=best[i - 1][j + (1 << (i - 1))]; if(height[a] < height[b]) best[i][j] = a; else best[i][j] = b; } } int askRMQ(int a,int b) { int t; t=mm[b - a + 1]; b -= (1 << t) - 1; a = best[t][a];b = best[t][b]; return height[a]<height[b] ? a : b; } int lcp(int a,int b) { a = Rank[a];b = Rank[b]; if(a > b)swap(a,b); return height[askRMQ(a + 1,b)]; } */ int num; int N,cas; bool vis[4010]; char str[210]; int belong[MAXN]; int ans[MAXN],tot; bool judge(int mid) { int step = 1; while (true) { while (step <= N && height[step] < mid) step++; if (step > N) break; memset(vis,false,sizeof(vis)); while (step <= N && height[step] >= mid) { int lft = belong[sa[step - 1]]; int rht = belong[sa[step]]; vis[lft] = vis[rht] = true; step++; } bool flag = false; for (int i = 0 ; i < num ; i++) { if (!vis[i]) { flag = true; break; } } if (!flag) return true; } return false; } int ret; void output(int length) { ret = INF; int step = 1; while (true) { while (step <= N && height[step] < length) step++; if (step > N) break; int Min = sa[step - 1]; memset(vis,false,sizeof(vis)); while (step <= N && height[step] >= length) { int lft = belong[sa[step - 1]]; int rht = belong[sa[step]]; vis[lft] = vis[rht] = true; step++; } bool flag = false; for (int i = 0 ; i < num ; i++) { if (!vis[i]) { flag = true; break; } } if (!flag) { ret = Min; break; } } for (int i = 0,j = ret ; i < length ; i++,j++) printf("%c",r[j] - 4005); putchar(' '); } int main() { while (scanf("%d",&num) != EOF) { if (num == 0) break; cas = 0; int step = 0; for (int i = 0 ; i < num ; i++) { scanf("%s",str); int len = strlen(str); for (int j = 0 ; j < len ; j++) { belong[cas] = i; r[cas++] = str[j] + 4005; } belong[cas] = -1; r[cas++] = step; step++; } cas--; N = cas; build_sa(r,N + 1,5000); getHeight(r,N); // for (int i = 0 ; i <= N ; i++) printf("%d ",r[i]); puts(""); int ans = 0,L = 1,R = 256; while (L <= R) { int mid = (L + R) / 2; if (judge(mid)) { ans = mid; L = mid + 1; } else R = mid -1; } // printf("%d ",ans); if (ans == 0) puts("IDENTITY LOST"); else { output(ans); } } return 0; }
HDU 2609 How many最小表示法在统计
FZU 1901 求所有满足s[i] == s[i + k](所有i)的所有k 依然求循环节

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; char str[MAXN]; int fail[MAXN]; int ans[MAXN],tot; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } int main() { int T,kase = 1; scanf("%d",&T); while (T--) { scanf("%s",str); int len = strlen(str); tot = 0; ans[tot++] = len; kmp_pre(str,len,fail); int cur = len; while (fail[cur] > 0) { ans[tot++] = fail[cur]; cur = fail[cur]; } for (int i = 1 ; i < tot ; i++) ans[i] = len - ans[i]; sort(ans,ans + tot); printf("Case #%d: %d ",kase++,tot); for (int i = 0 ; i < tot ; i++) printf("%d%c",ans[i], i == tot - 1 ? ' ' : ' '); } return 0; }
HDU 4763 求同时出现在前缀后缀中间且不重叠的最长串
直接利用KMP暴力2次

#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 1000010; char str[MAXN]; int fail[MAXN]; void kmp_pre(char x[],int m,int fail[]) { int i = 0,j; j = fail[0] = -1; while (i < m) { while (j != -1 && x[i] != x[j]) j = fail[j]; fail[++i] = ++j; } } bool flag[MAXN]; int main() { int T; scanf("%d",&T); while (T--) { scanf("%s",str); int len = strlen(str); kmp_pre(str,len,fail); memset(flag,false,sizeof(flag)); int cur = len; while (cur > 0) { if(cur * 2 <= len) flag[cur] = true; cur = fail[cur]; } int ans = 0; for (int i = len - 1 ; i > 1 ; i--) { cur = i; while (cur > 0) { if (flag[cur] && i >= 2 * cur && cur + i <= len) { ans = max(ans,cur); break; } cur = fail[cur]; } } printf("%d ",ans); } return 0; }