kuangbin专题十六 KMP & 扩展KMP & Manacher
1.HDU - 1711
kmp模板题,只是从字符串变成了整数数组。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int a[N],b[N];
int n,m,ne[N];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
for(int i=2,j=0;i<=m;i++){
while(j&&b[i]!=b[j+1]) j=ne[j];
if(b[i]==b[j+1]) j++;
ne[i]=j;
}
int res=-1;
for(int i=1,j=0;i<=n;i++){
while(j&&a[i]!=b[j+1]) j=ne[j];
if(a[i]==b[j+1]) j++;
if(j==m){
res=i-m+1;
break;
}
}
printf("%d\n",res);
}
return 0;
}
2. HDU - 1686
kmp求子串出现的次数(可重复)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char w[N],t[N];
int ne[N];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%s%s",w+1,t+1);
int n=strlen(w+1),m=strlen(t+1);
for(int i=2,j=0;i<=n;i++){
while(j&&w[i]!=w[j+1]) j=ne[j];
if(w[i]==w[j+1]) j++;
ne[i]=j;
}
int res=0;
for(int i=1,j=0;i<=m;i++){
while(j&&t[i]!=w[j+1]) j=ne[j];
if(t[i]==w[j+1]) j++;
if(j==n){
res++;
j=ne[j];
}
}
printf("%d\n",res);
}
return 0;
}
3. HDU - 2087
求子串出现的次数(不可重复)
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
char a[N],b[N];
int ne[N];
void init(char p[],int n,int ne[]){
for(int i=2,j=0;i<=n;i++){
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
}
int kmp_match(char s[],char p[],int ne[],int n,int m){
int cnt = 0;
for(int i=1,j=0;i<=n;i++){
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==m){
cnt++;
j=0;
}
}
return cnt;
}
int main()
{
while(scanf("%s",a+1)&&a[1]!='#'){
scanf("%s",b+1);
int n=strlen(a+1),m=strlen(b+1);
init(b,m,ne);
printf("%d\n",kmp_match(a,b,ne,n,m));
}
return 0;
}
4.HDU - 3746
长度为 n n n的字符串的最小循环节的长度是n-next[n]。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char a[N];
int n;
int ne[N];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%s",a+1);
n=strlen(a+1);
for(int i=2,j=0;i<=n;i++){
while(j&&a[i]!=a[j+1]) j=ne[j];
if(a[i]==a[j+1]) j++;
ne[i]=j;
}
int len=n-ne[n];
if(len<n&&n%len==0) puts("0");
else printf("%d\n",len-n%len);
}
return 0;
}
5. HDU - 1358
kmp和循环节
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char a[N];
int ne[N];
int n;
int main()
{
int T=1;
while(scanf("%d",&n),n){
scanf("%s",a+1);
printf("Test case #%d\n",T++);
for(int i=2,j=0;i<=n;i++){
while(j&&a[i]!=a[j+1]) j=ne[j];
if(a[i]==a[j+1]) j++;
ne[i]=j;
int len=i-ne[i];
if(i%len==0&&i/len>1) printf("%d %d\n",i,i/len);
}
puts("");
}
return 0;
}
6. HUST - 1010
kmp与循环节,无法提交。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char a[N];
int ne[N];
int main()
{
while(~scanf("%s",a+1)){
int n=strlen(a+1);
for(int i=2,j=0;i<=n;i++){
while(j&&a[i]!=a[j+1]) j=ne[j];
if(a[i]==a[j+1]) j++;
ne[i]=j;
}
printf("%d\n",n-ne[n]);
}
return 0;
}
7. POJ - 2406
kmp与循环节
#include<cstdio>
#include<cstring>
const int N=1e6+10;
char a[N];
int ne[N];
int main()
{
while(scanf("%s",a+1),a[1]!='.'){
int n=strlen(a+1);
for(int i=2,j=0;i<=n;i++){
while(j&&a[i]!=a[j+1]) j=ne[j];
if(a[i]==a[j+1]) j++;
ne[i]=j;
}
int len=n-ne[n];
if(n%len==0) printf("%d\n",n/len);
else puts("1");
}
return 0;
}
8. POJ - 2752
求出所有长度的公共前后缀,用while模拟多次求next[n]的操作即可。
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=4e5+10;
char a[N];
int ne[N];
int main()
{
while(~scanf("%s",a+1)){
int n=strlen(a+1);
vector<int> v;
v.push_back(n);
for(int i=2,j=0;i<n;i++){
while(j&&a[i]!=a[j+1]) j=ne[j];
if(a[i]==a[j+1]) j++;
ne[i]=j;
}
ne[0]=-1;
int j=ne[n-1];
while(j>=0){
if(a[n]==a[j+1]) v.push_back(j+1);
j=ne[j];
}
for(int i=v.size()-1;i>=0;i--) printf("%d ",v[i]);
puts("");
}
return 0;
}
9. POJ - 3080
暴力枚举
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int N=15;
string s[N];
int n;
int main()
{
int T;
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i];
string res;
for(int len=3;len<=s[1].size();len++){
for(int i=0;i+len-1<s[1].size();i++){
string str=s[1].substr(i,len);
bool flag=true;
for(int j=2;j<=n;j++){
if(s[j].find(str)==-1){
flag=false;
break;
}
}
if(flag&&(str.size()>res.size()||(str.size()==res.size()&&str<res))) res=str;
}
}
if(res.size()>=3) cout<<res<<endl;
else cout<<"no significant commonalities"<<endl;
}
return 0;
}
10. HDU - 2594
kmp和扩展kmp都可以做
kmp做法
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];
int ne[N];
int main()
{
while(~scanf("%s",s+1)){
int len1=strlen(s+1);
scanf("%s",s+1+len1);
int len2=strlen(s+1+len1);
int n=len1+len2;
for(int i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
}
int res=0;
ne[0]=-1;
int j=ne[n-1];
while(j>=0){
if(s[n]==s[j+1]&&j+1<=min(len1,len2)){
res=j+1;
break;
}
j=ne[j];
}
if(res){
for(int i=1;i<=res;i++) printf("%c",s[i]);
printf(" %d\n",res);
}
else puts("0");
}
return 0;
}
exkmp做法
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
char s1[N],s2[N];
int z[N],exd[N];
void init(char p[],int n,int z[]){
for(int i=1;i<=n;i++) z[i]=0;
z[1]=n;
for(int i=2,l=0,r=0;i<=n;i++){
if(i<=r) z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=n&&p[i+z[i]]==p[1+z[i]]) z[i]++;
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
}
int exkmp(char s[],char p[],int n,int m,int z[],int exd[]){
init(p,m,z);
for(int i=1;i<=n;i++) exd[i]=0;
for(int i=1,l=0,r=0;i<=n;i++){
if(i<=r) exd[i]=min(z[i-l+1],r-i+1);
while(i+exd[i]<=n&&s[i+exd[i]]==p[1+exd[i]]) exd[i]++;
if(i+exd[i]-1==n){
return exd[i];
}
if(i+exd[i]-1>r) l=i,r=i+exd[i]-1;
}
return 0;
}
int main()
{
while(~scanf("%s",s1+1)){
scanf("%s",s2+1);
int m=strlen(s1+1),n=strlen(s2+1);
int res=exkmp(s2,s1,n,m,z,exd);
if(res){
for(int i=1;i<=res;i++) printf("%c",s1[i]);
printf(" %d\n",res);
}
else puts("0");
}
return 0;
}
11. HDU - 3336
如果匹配过程中每个字符可以使用多次的话答案就是Z函数的和。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,mod=10007;
int n;
char s[N];
int z[N];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++) z[i]=0;
z[1]=n;
for(int i=2,l=0,r=0;i<=n;i++){
if(i<=r) z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=n&&s[i+z[i]]==s[1+z[i]]) z[i]++;
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
int res=0;
for(int i=1;i<=n;i++) res=(res+z[i])%mod;
printf("%d\n",res);
}
return 0;
}
12. HDU - 4300
题意十分折磨,做法就是用exkmp求后半段明文的后缀和前半段密文的最大公共前缀。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char t[30],rev[30],s[N],p[N];
int z[N],exd[N];
void init(char p[],int n,int z[]){
for(int i=1;i<=n;i++) z[i]=0;
z[1]=n;
for(int i=2,l=0,r=0;i<=n;i++){
if(i<=r) z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=n&&p[i+z[i]]==p[1+z[i]]) z[i]++;
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
}
int exkmp(char s[],char p[],int n,int m,int z[],int exd[]){
init(p,m,z);
for(int i=1;i<=n;i++) exd[i]=0;
for(int i=1,l=0,r=0;i<=n;i++){
if(i<=r) exd[i]=min(z[i-l+1],r-i+1);
while(i+exd[i]<=n&&s[i+exd[i]]==p[1+exd[i]]) exd[i]++;
if(i-1>=exd[i]&&i+exd[i]-1==n){
return i-1;
}
if(i+exd[i]-1>r) l=i,r=i+exd[i]-1;
}
return n;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%s%s",t,s+1);
for(int i=0;i<26;i++) rev[t[i]-'a']='a'+i;
int n=strlen(s+1);
for(int i=1;i<=n;i++) p[i]=rev[s[i]-'a'];
int len=exkmp(s,p,n,n,z,exd);
for(int i=1;i<=len;i++) printf("%c",s[i]);
for(int i=1;i<=len;i++) printf("%c",rev[s[i]-'a']);
puts("");
}
return 0;
}
13. HDU - 1238
暴力枚举
#include<bits/stdc++.h>
using namespace std;
const int N=110;
string s[N];
int n;
bool check(string str){
for(int i=2;i<=n;i++)
if(s[i].find(str)==-1) return false;
return true;
}
int main()
{
int T;
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i];
int res=0;
for(int len=1;len<s[1].size();len++){
for(int i=0;i+len-1<s[1].size();i++){
string str=s[1].substr(i,len);
string rev(str.rbegin(),str.rend());
if(check(str)||check(rev)){
res=len;
break;
}
}
}
cout<<res<<endl;
}
return 0;
}
14. HDU - 2328
暴力枚举
#include<bits/stdc++.h>
using namespace std;
const int N=4010;
string s[N];
int n;
bool check(string str){
for(int i=2;i<=n;i++)
if(s[i].find(str)==-1) return false;
return true;
}
int main()
{
while(cin>>n,n){
for(int i=1;i<=n;i++) cin>>s[i];
string res;
for(int len=1;len<s[1].size();len++){
for(int i=0;i+len-1<s[1].size();i++){
string str=s[1].substr(i,len);
if(check(str)&&((str.size()>res.size())||(str.size()==res.size()&&str<res))){
res=str;
}
}
}
if(res.size()) cout<<res<<endl;
else cout<<"IDENTITY LOST"<<endl;
}
return 0;
}
15. HDU - 3374
kmp求循环节个数,最小表示法求起始位置
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
int n;
int ne[N];
void get_next(char p[],int n,int ne[]){
for(int i=2,j=0;i<=n;i++){
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
}
int express_min(char s[],int n){
int k=0,i=0,j=1;
while(k<n&&i<n&&j<n){
if(s[(i+k)%n]==s[(j+k)%n]) k++;
else{
s[(i+k)%n]>s[(j+k)%n]?i+=k+1:j+=k+1;
if(i==j) i++;
k=0;
}
}
return min(i,j);
}
int express_max(char s[],int n){
int k=0,i=0,j=1;
while(k<n&&i<n&&j<n){
if(s[(i+k)%n]==s[(j+k)%n]) k++;
else{
s[(i+k)%n]<s[(j+k)%n]?i+=k+1:j+=k+1;
if(i==j) i++;
k=0;
}
}
return min(i,j);
}
int main()
{
while(~scanf("%s",s+1)){
int n=strlen(s+1);
get_next(s,n,ne);
int num=n/(n-ne[n]);
printf("%d %d %d %d\n",express_min(s+1,n)+1,num,express_max(s+1,n)+1,num);
}
return 0;
}
16. HDU - 2609
将所有字符串转换成最小表示存在集合中,集合的大小就是答案。
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char s[N];
int n;
int express_min(char s[],int n){
int k=0,i=0,j=1;
while(k<n&&i<n&&j<n){
if(s[(i+k)%n]==s[(j+k)%n]) k++;
else{
s[(i+k)%n]>s[(j+k)%n]?i+=k+1:j+=k+1;
if(i==j) i++;
k=0;
}
}
return min(i,j);
}
int main()
{
while(~scanf("%d",&n)){
set<string> se;
for(int i=0;i<n;i++){
scanf("%s",s);
int m=strlen(s);
int p=express_min(s,m);
string str;
for(int j=0;j<m;j++) str+=s[(p+j)%m];
se.insert(str);
}
printf("%d\n",se.size());
}
return 0;
}
17. FZU - 1901
本质还是求所有的公共前后缀的长度,用kmp做就行。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
int ne[N];
int main()
{
int T;
scanf("%d",&T);
for(int _=1;_<=T;_++){
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=2,j=0;i<n;i++){
while(j&&s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
}
vector<int> res;
ne[0]=-1;
int j=ne[n-1];
while(j>=0){
if(s[n]==s[j+1]) res.push_back(n-j-1);
j=ne[j];
}
res.push_back(n);
printf("Case #%d: %d\n",_,res.size());
for(int i=0;i<res.size();i++) printf("%d ",res[i]);
puts("");
}
return 0;
}
18. POJ - 3746
感觉有点恶心,不是很想写,想知道做法的可以去找其他人的代码。
19. HDU - 3613
先通过manacher得到以每个点为中心的最长回文串长度,再枚举一遍分割点得到答案。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
char s[N],mn[N*2];
int w[30];
int len[N*2],pre[N];
void manacher(char s[],int n,char mn[],int len[]){
mn[0]=mn[1]='#';
int k=1;
for(int i=1;i<=n;i++){
mn[++k]=s[i];
mn[++k]='#';
}
n=k;
for(int i=1,mid=0,r=0;i<=n;i++){
len[i]=i<=r?min(len[(mid<<1)-i],r-i+1):1;
while(mn[i-len[i]]==mn[i+len[i]]) len[i]++;
if(i+len[i]-1>r) mid=i,r=i+len[i]-1;
}
}
int get(int l,int r){
if(len[l+r]>=r-l+1) return pre[r]-pre[l-1];
return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
for(int i=0;i<26;i++) scanf("%d",&w[i]);
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+w[s[i]-'a'];
manacher(s,n,mn,len);
int res=-1e9;
for(int i=1;i<n;i++){
res=max(res,get(1,i)+get(i+1,n));
}
printf("%d\n",res);
}
return 0;
}
20. POJ - 3376
manacher和trie,有点绕,感觉边界处理起来有点麻烦,但是很奇怪的是写了两个版本都能过,不知道是不是数据太弱了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=2e6+10;
char s[N],t[N];
int trie[N][26],cnt[N],pcnt[N],idx;
int l[N],r[N];
int mn[N*2],len[N*2];
int n;
bool is_pal[N];
void manacher(char s[],int l,int r){
mn[0]=mn[1]='#';
int k=1;
for(int i=l;i<=r;i++){
mn[++k]=s[i];
mn[++k]='#';
}
int n=k;
for(int i=1,mid=0,right=0;i<=n;i++){
len[i]=i<=right?min(len[(mid<<1)-i],right-i+1):1;
while(mn[i-len[i]]==mn[i+len[i]]) len[i]++;
if(i+len[i]-1>right) mid=i,right=i+len[i]-1;
}
for(int i=l;i<=r;i++){
if(len[i+r-2*l+2]>=r-i+1){
is_pal[i]=true;
}
}
}
void insert(char s[],int l,int r){
int p=0;
for(int i=l;i<=r;i++){
int c=s[i]-'a';
if(!trie[p][c]) trie[p][c]=++idx;
p=trie[p][c];
if(i<r&&is_pal[i+1]) pcnt[p]++;
}
cnt[p]++;
pcnt[p]++;
}
int query(char s[],int l,int r){
int p=0,res=0;
for(int i=l;i<=r;i++){
int c=s[i]-'a';
p=trie[p][c];
if(!p) break;
if(i<r&&is_pal[i+1]) res+=cnt[p];
}
if(p) res+=pcnt[p];
return res;
}
int main()
{
scanf("%d",&n);
int cur=1;
for(int i=1;i<=n;i++){
int len;
scanf("%d%s",&len,s+cur);
l[i]=cur,r[i]=cur+len-1;
for(int j=l[i];j<=r[i];j++) t[j]=s[l[i]+r[i]-j];
cur+=len;
}
for(int i=1;i<=n;i++){
manacher(s,l[i],r[i]);
insert(s,l[i],r[i]);
}
LL res=0;
memset(is_pal,0,sizeof is_pal);
for(int i=1;i<=n;i++){
manacher(t,l[i],r[i]);
res+=query(t,l[i],r[i]);
}
printf("%lld\n",res);
return 0;
}
21. POJ - 3974
manacher模板题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
char s[N];
char mn[N*2];
int len[N*2];
void manacher(char s[],int n){
mn[0]=mn[1]='#';
int k=1;
for(int i=1;i<=n;i++){
mn[++k]=s[i];
mn[++k]='#';
}
n=k;
for(int i=1,mid=0,r=0;i<=n;i++){
len[i]=i<r?min(len[(mid<<1)-i],r-i+1):1;
while(mn[i-len[i]]==mn[i+len[i]]) len[i]++;
if(i+len[i]-1>r) mid=i,r=i+len[i]-1;
}
}
int main()
{
int T=1;
while(scanf("%s",s+1),s[1]!='E'){
int n=strlen(s+1);
manacher(s,n);
int res=0;
for(int i=1;i<=2*n;i++) res=max(res,len[i]-1);
printf("Case %d: %d\n",T++,res);
}
return 0;
}
22. HDU - 4513
主要还是manacher算法的思想,只是在逐个对比的时候多加一点限制,可以分情况讨论也可以直接用 i i i和 i + 2 i+2 i+2比大小,因为加了分隔符保证了这样要么是分隔符之间的比较要么就是真正数字之间的比较,更加简洁。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],mn[N*2],len[N*2];
int n;
void manacher(int a[],int n){
mn[0]=mn[1]=-1;
int k=1;
for(int i=1;i<=n;i++){
mn[++k]=a[i];
mn[++k]=-1;
}
n=k;
for(int i=1,mid=0,r=0;i<=n;i++){
len[i]=i<=r?min(len[(mid<<1)-i],r-i+1):1;
while(mn[i-len[i]]==mn[i+len[i]]&&(mn[i-len[i]]<=mn[i-len[i]+2])) len[i]++;
if(i+len[i]-1>r) mid=i,r=i+len[i]-1;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
manacher(a,n);
int res=0;
for(int i=1;i<=2*n;i++) res=max(res,len[i]-1);
printf("%d\n",res);
}
return 0;
}
23. HDU - 3294
manacher模板题,要想想怎么得到原回文串的起始位置。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char a[2],s[N];
int mn[N*2],len[N*2];
void manacher(char s[],int n){
mn[0]=mn[1]='#';
int k=1;
for(int i=1;i<=n;i++){
mn[++k]=s[i];
mn[++k]='#';
}
n=k;
for(int i=1,mid=0,r=0;i<=n;i++){
len[i]=i<=r?min(len[(mid<<1)-i],r-i+1):1;
while(mn[i-len[i]]==mn[i+len[i]]) len[i]++;
if(i+len[i]-1>r) mid=i,r=i+len[i]-1;
}
}
int main()
{
while(~scanf("%s %s",a,s+1)){
int n=strlen(s+1);
int t=a[0]-'a';
for(int i=1;i<=n;i++) s[i]=(s[i]-'a'-t+26)%26+'a';
manacher(s,n);
int res=0,p;
for(int i=1;i<=2*n;i++){
if(len[i]-1>res){
res=len[i]-1;
p=(i-len[i]+2)/2;
}
}
if(res<2) puts("No solution!");
else{
s[p+res]='\0';
printf("%d %d\n%s\n",p-1,p+res-2,s+p);
}
}
return 0;
}
24. HDU - 3068
manacher模板题
#include<bits/stdc++.h>
using namespace std;
const int N=110010;
char s[N],mn[N*2];
int len[N*2];
void manacher(char s[],int n,char mn[],int len[]){
mn[0]=mn[1]='#';
int k=1;
for(int i=1;i<=n;i++){
mn[++k]=s[i];
mn[++k]='#';
}
for(int i=1,mid=0,r=0;i<=k;i++){
len[i]=i<=r?min(len[(mid<<1)-i],r-i+1):1;
while(mn[i+len[i]]==mn[i-len[i]]) len[i]++;
if(i+len[i]-1>r) mid=i,r=i+len[i]-1;
}
}
int main()
{
while(~scanf("%s",s+1)){
int n=strlen(s+1);
manacher(s,n,mn,len);
int res=0;
for(int i=1;i<=2*n;i++) res=max(res,len[i]-1);
printf("%d\n",res);
}
return 0;
}
25. HDU - 4847
因为模式串很短,所以直接暴力也不会超时
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];
int ans,ne[N];
int main()
{
char p[5]="doge";
while(~scanf("%s",s)){
int n=strlen(s);
for(int i=0;i+3<n;i++){
bool flag=true;
for(int j=0;j<4;j++)
if(s[i+j]!=p[j]&&s[i+j]!=p[j]-32){
flag=false;
break;
}
if(flag) ans++;
}
}
printf("%d\n",ans);
return 0;
}
26. HDU - 4763
用next数组枚举所有的公共前后缀,然后判断在中段能否匹配。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
int ne[N];
bool kmp(char s[],char p[],int n,int m,int ne[]){
for(int i=1,j=0;i<=n;i++){
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==m){
return true;
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%s",s+1);
int n=strlen(s+1);
ne[0]=0;
for(int i=2,j=0;i<n;i++){
while(j&&s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
}
int res=0;
ne[0]=-1;
int j=ne[n-1];
while(j>=0){
if(s[n]==s[j+1]){
if((j+1)*3<=n&&kmp(s+j+1,s,n-2*j-2,j+1,ne)){
res=j+1;
break;
}
}
j=ne[j];
}
printf("%d\n",res);
}
return 0;
}