kuangbin专题十六 KMP & 扩展KMP & Manacher

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值