Kuangbin 带你飞 KMP扩展KMP Manacher
首先是几份模版
KMP
void kmp_pre(char x[],int m,int fail[])
{
int i,j;
j = fail[] = -;
i = ;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int kmp_count(char x[],int m,char y[],int n)
{
int i = ,j = ;
int ans = ;
while (i < n)
{
while (j != - && 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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int getval(char * str,int len,bool type)
{
int i = ,j = ,k = ;
while (i < len && j < len && k < len)
{
int val = str[(j + k) % len] - str[(i + k) % len];
if (val == ) k++;
else
{
if (type)
{
if (val > ) j += k + ;
else i += k + ;
}
else
{
if (val > ) i += k + ;
else j += k + ;
}
k = ;
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]) ? : len / (len - fail[len]);
printf("%d %d %d %d\n",l + ,ret,r + ,ret);
}
return ;
}
扩展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 == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
char S[MAXN],T[MAXN];
int fail[MAXN];
int ext1[MAXN],ext2[MAXN];
int val[];
int sum[MAXN]; void pre_ekmp(char x[],int m,int fail[])
{
fail[] = m;
int j = ;
while (j + < m && x[j] == x[j + ]) j++;
fail[] = j;
int k = ;
for (int i = ; i < m ; i++)
{
int p = fail[k] + k - ;
int L = fail[i - k];
if (i + L < p + ) fail[i] = L;
else
{
j = max(,p - i + );
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 = ;
while (j < n && j < m && x[j] == y[j])j++;
extend[] = j;
int k = ;
for (int i = ; i < n ; i++)
{
int p = extend[k] + k - ;
int L = fail[i - k];
if (i + L < p + ) extend[i] = L;
else
{
j = max(,p - i + );
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 = ; i < ; i++) scanf("%d",&val[i]);
scanf("%s",S);
memset(sum,,sizeof(sum));
int len = strlen(S);
for (int i = ; i < len ; i++)
sum[i + ] = sum[i] + val[S[i] - 'a'];
for (int j = len - ,i = ; j >= ;j--,i++)
T[i] = S[j];
T[len] = '\0';
// printf("%s %s\n",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 = ;
for (int i = ; i < len ; i++)
{
if (i > && ext1[i] + i == len)
{
int pos = ext1[i];
int res = sum[pos];
// printf("%d %d\n",i,res);
if (ext2[pos] + pos == len)
{
res += sum[len] - sum[pos];
}
// printf("%d %d\n",i,res);
ret = max(res,ret);
}
else
{
int pos = i + ;
int res = ;
if (ext2[pos] + pos == len)
res += sum[len] - sum[pos];
ret = max(ret,res);
}
}
printf("%d\n",ret);
}
return ;
}
模版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 == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXD = ;
struct node
{
int num;
int tot;
node * nxt[MAXD];
}src[MAXN]; node * root;
int st[MAXN],ed[MAXN];
bool flag[][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 = ;
while (lft + + j <= rht && x[lft + j] == x[lft + j + ]) j++;
fail[lft + ] = j;
int k = lft + ;
for (int i = lft + ; i <= rht ; i++)
{
int p = fail[k] + k - ;
int L = fail[lft + i - k];
if (L + i < p + ) fail[i] = L;
else
{
j = max(,p - i + );
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 = ;
while (j + lft <= rht && S[j + lft] == T[lft + j])j++;
extend[lft] = j;
int k = lft;
for (int i = lft + ; i <= rht ; i++)
{
int p = extend[k] + k - ;
int L = fail[lft + i - k];
if (L + i < p + ) extend[i] = L;
else
{
j = max(,p - i + );
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 + )
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[][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[][i + ]) || i == rht)
ret += u -> num;
}
if (u != NULL) ret += u -> tot;
} int main()
{
int N;
while (scanf("%d",&N) != EOF)
{
ret = ;
cas = ;
memset(src,,sizeof(src));
memset(flag,false,sizeof(flag));
root = &src[cas++];
int length = ;
for (int i = ; i < N ; i++)
{
int d;
scanf("%d%s",&d,S + length);
for (int j = ; j < d ; j++)
T[length + j] = S[length + d - - j];
st[i] = length;
ed[i] = length + d - ;
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 = ; i < N ; i++)
Find(T,st[i],ed[i]);
printf("%I64d\n",ret);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char ma[MAXN * ];
int mp[MAXN * ]; void Manacher(char str[],int len)
{
int l = ;
ma[l++] = '$';
ma[l++] = '#';
for (int i = ; i < len ; i++)
{
ma[l++] = str[i];
ma[l++] = '#';
}
ma[l] = ;
int mx = ,id = ;
for (int i = ; i < l ; i++)
{
mp[i] = mx > i ? min(mp[ * id - i],mx - i) : ;
while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++;
if (i + mp[i] > mx)
{
mx = i + mp[i];
id = i;
}
}
int ret = ;
for (int i = ; i < l ; i++)
ret = max(ret,mp[i] - );
printf("%d\n",ret);
}
char str[MAXN]; int main()
{
int kase = ;
while (scanf("%s",str) != EOF)
{
if (strcmp(str,"END") == ) break;
printf("Case %d: ",kase++);
Manacher(str,strlen(str));
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
int ma[MAXN * ];
int mp[MAXN * ];
int src[MAXN],N; void manacher(int str[],int len)
{
int l = ;
ma[l++] = '$';
ma[l++] = '#';
for (int i = ; i < len ; i++)
{
ma[l++] = str[i];
ma[l++] = '#';
}
ma[l] = ;
int mx = ,id = ;
for (int i = ; i < l ; i++)
{
mp[i] = mx > i ? min(mp[ * id - i],mx - i) : ;
while(ma[i + mp[i]] == ma[i - mp[i]] && ma[i - mp[i]] <= ma[i - mp[i] + ])
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 = ;
for (int i = ; i < l ; i++) ret = max(ret,mp[i] - );
printf("%d\n",ret);
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&N);
for (int i = ; i < N ; i++) scanf("%d",&src[i]);
manacher(src,N);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char ma[MAXN * ];
int mp[MAXN * ];
int idx[MAXN * ];
char str[MAXN];
map<char,char>res; void Manacher(char str[],int len)
{
memset(idx,-,sizeof(idx));
int l = ;
ma[l++] = '$';
ma[l++] = '#';
for (int i = ; i < len ; i++)
{
idx[l] = i;
ma[l++] = str[i];
idx[l] = i;
ma[l++] = '#';
}
ma[l] = ;
int mx = ,id = ;
for (int i = ; i < l ; i++)
{
mp[i] = mx > i ? min(mp[ * id - i],mx - i) : ;
while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++;
if (i + mp[i] > mx)
{
mx = i + mp[i];
id = i;
}
}
int ret = ,post;
for (int i = ; i < l ; i++)
{
if (str[i] != '#' && str[i] != '$' && mp[i] - > ret)
{
ret = mp[i] - ;
post = i;
}
}
if (ret == ) puts("No solution!");
else
{
if (ret % )
{
printf("%d %d\n",idx[post] - (ret - ) / ,idx[post] + (ret - ) / );
for (int j = idx[post] - (ret - ) / ; j <= idx[post] + (ret - ) / ; j++)
printf("%c",str[j]);
puts("");
}
else
{
printf("%d %d\n",idx[post] - ret / + ,idx[post] + ret / );
for (int j = idx[post] - ret / + ; j <= idx[post] + ret / ; j++)
printf("%c",str[j]);
puts("");
}
}
} int main()
{
char op[];
while (scanf("%s%s",op,str) != EOF)
{
res.clear();
int pos = op[] - 'a';
for (int i = ,j = pos ; i < ; i++,j = (j + ) % )
res[j + 'a'] = i + 'a';
int len = strlen(str);
for (int i = ; i < len ; i++)
{
str[i] = res[str[i]];
}
Manacher(str,len);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXD = ;
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[] = -;
i = ;
while (i < m)
{
while (j != - && 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 = ;
i = j = ;
while (i < n)
{
while (j != - && y[i] != x[j]) j = fail[j];
i++;j++;
if (j >= m)
{
return i - m;
ans++;
j = fail[j];
}
}
return -;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
for (int i = ; i < N ; i++) scanf("%d",&src[i]);
for (int i = ; i < M ; i++) scanf("%d",&tag[i]);
kmp_pre(tag,M,fail);
int ret = kmp_count(tag,M,src,N);
printf("%d\n",ret == - ? - : ret + );
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXD = ;
char src[MAXN],tag[MAXD];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i,j;
j = fail[] = -;
i = ;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int kmp_count(char x[],int m,char y[],int n)
{
int i = ,j = ;
int ans = ;
while (i < n)
{
while (j != - && 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\n",ret);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char src[MAXN],tag[MAXN];
int fail[MAXN];
int tot,pos[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} void kmp_count(char x[],int m,char y[],int n)
{
int i = , j = ;
int ans = ;
while (i < n)
{
while (j != - && 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[] == '#') break;
scanf("%s",tag);
int m = strlen(tag);
kmp_pre(tag,m,fail);
int n = strlen(src);
tot = ;
kmp_count(tag,m,src,n);
if (tot == )
{
puts("");
continue;
}
int ret = ,pre = ;
for (int i = ; i < tot ; i++)
{
if (pos[i] - pos[pre] >= m)
{
ret++;
pre = i;
}
}
printf("%d\n",ret);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char src[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && 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] != && len % (len - fail[len]) == )
{
puts("");
continue;
}
else
{
printf("%d\n",(len - fail[len]) - fail[len] % (len - fail[len]));
}
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int main()
{
int kase = ;
int m;
while (scanf("%d",&m) != EOF)
{
if (m == ) break;
printf("Test case #%d\n",kase++);
scanf("%s",str);
kmp_pre(str,m,fail);
for (int i = ; i <= m ; i++)
{
if (i % (i - fail[i]) == )
{
if (i / (i - fail[i]) > )
printf("%d %d\n",i,i / (i - fail[i]));
}
}
puts("");
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && 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\n",len - fail[len]);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && 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 = ;
int cur = len;
ret[tot++] = len;
while (fail[cur] > )
{
ret[tot++] = fail[cur];
cur = fail[cur];
}
sort(ret,ret + tot);
for (int i = ; i < tot ; i++)printf("%d ",ret[i]);puts("");
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN],src[MAXN];
int fail[MAXN];
struct node
{
char word[];
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[] = -;
i = ;
while (i < m)
{
while (j != - && 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 = ;
while(i < n)
{
while (j != - && 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 = ; i < N ; i++)
{
scanf("%s",res[i].word);
res[i].length = strlen(res[i].word);
}
sort(res,res + N);
char tmp[],cmp[];
int ret = ;
for (int l = ; l < res[].length ; l++)
{
for (int r = l ; r < res[].length ; r++)
{
int leap = ;
for (int i = l ; i <= r ; i++)
tmp[leap++] = res[].word[i];
tmp[leap] = '\0';
bool flag = false;
kmp_pre(tmp,leap,fail);
for (int i = ; i < N ; i++)
{
if (!kmp_find(tmp,leap,res[i].word,res[i].length))
{
flag = true;
break;
}
}
if (!flag)
{
if (r - l + > ret)
{
ret = r - l + ;
int step = ;
for (int i = l ; i <= r ; i++)
cmp[step++] = res[].word[i];
cmp[step] = '\0';
}
else if (r - l + == ret)
{
if (strcmp(tmp,cmp) < ) strcpy(cmp,tmp);
}
}
}
}
if (ret < ) printf("no significant commonalities\n");
else
{
printf("%s\n",cmp);
}
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && 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] == )
{
puts("");
continue;
}
for (int i = ; i < min(res,min(tmp,fail[len])) ; i++)
printf("%c",str[i]);
putchar(' ');
printf("%d\n",min(res,min(tmp,fail[len])));
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MOD = ;
char str[MAXN];
int fail[MAXN],num[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int main()
{
int T,kase = ;
scanf("%d",&T);
while (T--)
{
int N;
scanf("%d",&N);
scanf("%s",str);
kmp_pre(str,N,fail);
memset(num,,sizeof(num));
for (int i = ; i <= N ; i++)
num[fail[i]] = (num[fail[i]] + ) % MOD;
int sum = ;
for (int i = ; i <= N ; i++)
{
if (num[i] == ) sum = (sum + ) % MOD;
else sum = (sum + num[i] + ) % MOD;
}
printf("%d\n",sum);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
int fail[MAXN];
char trans[],str[MAXN];
int pos[MAXN];
char tag[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int kmp_count(char x[],int m,char y[])
{
int i = , j = ;
int n = strlen(y);
while (i < n)
{
while (j != - && 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 = ; i < ; i++) pos[trans[i] - 'a'] = i;
for (int i = ; i < len ; i++) tag[i] = pos[str[i] - 'a'] + 'a';
tag[len] = '\0';
kmp_pre(tag,len,fail);
int ret = kmp_count(tag,len,str + (len + ) / );
for (int i = ; i < len - ret ; i++)
printf("%c",str[i]);
for (int i = ; i < len - ret ; i++)
printf("%c",tag[i]);
puts("");;
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
int pos,N;
int fail[MAXN];
char src[MAXN],tag[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} bool kmp_count(char x[],int m,char y[],int n)
{
int i = ,j = ;
kmp_pre(x,m,fail);
while (i < n)
{
while (j != - && 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 = ; i < N ; i++)
{
if (i == pos) continue;
if (!kmp_count(str,leng,input[i],length[i] * )) return false;
}
return true;
} bool judge(int mid)
{
for (int i = ; i + mid <= length[pos]; i++)
{
char tmp[MAXN];
int cas = ;
for (int j = i ; j <= i + mid - ; j++)
tmp[cas++] = input[pos][j];
tmp[cas] = '\0';
if (can(tmp)) return true;
}
return false;
} void dealinput()
{
scanf("%d",&N);
pos = ;
for (int i = ; i < N ; i++)
{
scanf("%s",input[i]);
length[i] = strlen(input[i]);
if (length[i] < length[pos])
pos = i;
for (int j = length[i] - ,k = length[i]; j >= ; j--,k++)
input[i][k] = input[i][j];
input[i][length[i] * ] = '\0';
}
// for (int i = 0 ; i < N ; i++)
// printf("%s %d\n",input[i],length[i]);
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
dealinput();
int L = ,R = ;
int ans = ;
while (L <= R)
{
int mid = (L + R) / ;
if (judge(mid))
{
ans = mid;
L = mid + ;
}
else R = mid - ;
}
printf("%d\n",ans);
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
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 = ; i < m ; i++) c[i] = ;
for(i = ; i < n ; i++) c[x[i] = s[i]]++;
for(i = ; i < m ; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[i]]] = i;
for(j = ; j <= n ; j <<= )
{
p=;
for(i = n - j ; i < n ; i++) y[p++] = i;
for(i = ; i < n ; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
for(i = ; i < m ; i++) c[i] = ;
for(i = ; i < n ; i++) c[x[y[i]]]++;
for(i = ; i < m ; i++) c[i]+=c[i-];
for(i = n - ; i >= ; i--) sa[--c[x[y[i]]]] = y[i];
swap(x,y);
p = ;
x[sa[]] = ;
for(i = ; i < n ; i++)
x[sa[i]] = y[sa[i - ]] == y[sa[i]] && y[sa[i - ] + j] == y[sa[i] + j] ? p - : p++;
if(p >= n)break;
m = p;
}
} void getHeight(int s[],int n)
{
int i,j,k = ;
for(i = ;i <= n ; i++) Rank[sa[i]] = i;
for(i = ;i < n ; i++)
{
if(k)k--;
j = sa[Rank[i] - ];
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[];
char str[];
int belong[MAXN];
int ans[MAXN],tot; bool judge(int mid)
{
int step = ;
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 - ]];
int rht = belong[sa[step]];
vis[lft] = vis[rht] = true;
step++;
}
bool flag = false;
for (int i = ; 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 = ;
while (true)
{
while (step <= N && height[step] < length) step++;
if (step > N) break;
int Min = sa[step - ];
memset(vis,false,sizeof(vis));
while (step <= N && height[step] >= length)
{
int lft = belong[sa[step - ]];
int rht = belong[sa[step]];
vis[lft] = vis[rht] = true;
step++;
}
bool flag = false;
for (int i = ; i < num ; i++)
{
if (!vis[i])
{
flag = true;
break;
}
}
if (!flag)
{
ret = Min;
break;
}
}
for (int i = ,j = ret ; i < length ; i++,j++)
printf("%c",r[j] - );
putchar('\n');
} int main()
{
while (scanf("%d",&num) != EOF)
{
if (num == ) break;
cas = ;
int step = ;
for (int i = ; i < num ; i++)
{
scanf("%s",str);
int len = strlen(str);
for (int j = ; j < len ; j++)
{
belong[cas] = i;
r[cas++] = str[j] + ;
}
belong[cas] = -;
r[cas++] = step;
step++;
}
cas--;
N = cas; build_sa(r,N + ,);
getHeight(r,N);
// for (int i = 0 ; i <= N ; i++) printf("%d ",r[i]); puts("");
int ans = ,L = ,R = ;
while (L <= R)
{
int mid = (L + R) / ;
if (judge(mid))
{
ans = mid;
L = mid + ;
}
else R = mid -;
}
// printf("%d\n",ans);
if (ans == ) puts("IDENTITY LOST");
else
{
output(ans);
}
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN];
int ans[MAXN],tot; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = fail[j];
fail[++i] = ++j;
}
} int main()
{
int T,kase = ;
scanf("%d",&T);
while (T--)
{
scanf("%s",str);
int len = strlen(str);
tot = ;
ans[tot++] = len;
kmp_pre(str,len,fail);
int cur = len;
while (fail[cur] > )
{
ans[tot++] = fail[cur];
cur = fail[cur];
}
for (int i = ; i < tot ; i++) ans[i] = len - ans[i];
sort(ans,ans + tot);
printf("Case #%d: %d\n",kase++,tot);
for (int i = ; i < tot ; i++)
printf("%d%c",ans[i], i == tot - ? '\n' : ' ');
}
return ;
}
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 == ? b : gcd(b, a % b);}
const int MAXN = ;
char str[MAXN];
int fail[MAXN]; void kmp_pre(char x[],int m,int fail[])
{
int i = ,j;
j = fail[] = -;
while (i < m)
{
while (j != - && 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 > )
{
if(cur * <= len) flag[cur] = true;
cur = fail[cur];
}
int ans = ;
for (int i = len - ; i > ; i--)
{
cur = i;
while (cur > )
{
if (flag[cur] && i >= * cur && cur + i <= len)
{
ans = max(ans,cur);
break;
}
cur = fail[cur];
}
}
printf("%d\n",ans);
}
return ;
}
Kuangbin 带你飞 KMP扩展KMP Manacher的更多相关文章
- KUANGBIN带你飞
KUANGBIN带你飞 全专题整理 https://www.cnblogs.com/slzk/articles/7402292.html 专题一 简单搜索 POJ 1321 棋盘问题 //201 ...
- [kuangbin带你飞]专题1-23题目清单总结
[kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
- Tarjan 联通图 Kuangbin 带你飞 联通图题目及部分联通图题目
Tarjan算法就不说了 想学看这 https://www.byvoid.com/blog/scc-tarjan/ https://www.byvoid.com/blog/biconnect/ 下面是 ...
- 「kuangbin带你飞」专题十四 数论基础
layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...
- 「kuangbin带你飞」专题二十 斜率DP
layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...
- 「kuangbin带你飞」专题二十二 区间DP
layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...
- 「kuangbin带你飞」专题十九 矩阵
layout: post title: 「kuangbin带你飞」专题十九 矩阵 author: "luowentaoaa" catalog: true tags: mathjax ...
- 「kuangbin带你飞」专题十八 后缀数组
layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kua ...
- 「kuangbin带你飞」专题十七 AC自动机
layout: post title: 「kuangbin带你飞」专题十七 AC自动机 author: "luowentaoaa" catalog: true tags: - ku ...
随机推荐
- 【Linux运维】LNMP环境配置
安装准备: Centos7.3 MYSQL5.6 PHP5.6 NGINX1.10.3 一.安装Mysql mysql:[root@host129 src]#cd /usr/local/src/ [r ...
- 查看lwjgl常用状态的值
在遇到状态值较多较复杂的情况,可以选择使用GL11.glIsEnabled()或者GL11.glGet()函数来查看状态机值,以下是常用值: public static void printOpenG ...
- homework for Java
public class Dog { private String name; private String color; private int age; public Dog(String nam ...
- 【SSH】——spring的控制反转和依赖注入
spring是一个轻量级的容器框架,主要是为了使企业的开发变得简单.高效.无论是从大小还是开销来讲,他都可以算是轻量级的,也是非侵入性的. 下图是spring的框架示意图,说到spring,就不得不提 ...
- [C/C++] C++中new的语法规则
int *x = new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针) ); //开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址 ...
- XJOI NOIP模拟题2
第一题 组合计数 分析: 从前往后一位一位的计算 先算第一位比t小的数目,再算第一位与t[1]相同,第2位比t小的个数以此类推 先预处理一个数组h,h[i]表示从1~it串与s串不同的位数 对于第i位 ...
- 【bzoj1878】[SDOI2009]HH的项链 树状数组
题目描述 HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变得越来越长.有一 ...
- Walk 解题报告
Walk 题目描述 给定一棵 \(n\) 个节点的树,每条边的长度为 \(1\),同时有一个权值\(w\).定义一条路径的权值为路径上所有边的权值的最大公约数.现在对于任意 \(i \in [1,n] ...
- MySQL使用笔记(一)安装配置
By francis_hao Nov 27,2016 一般软件的安装都是可以通过源码和安装包安装,源码安装可配置性好些,安装包安装比较省事,况且使用yum也可以解决依赖的问题,基本实现了一键 ...
- 兔子与兔子 [Hash]
兔子与兔子 描述 很久很久以前,森林里住着一群兔子.有一天,兔子们想要研究自己的 DNA 序列.我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母) ...