[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher

kuangbin带你飞:点击进入新世界
三四个月之前挖的字符串坑:kmp初学状态 黑历史
回文串:不懂马拉车的可以点这里

总结:

本人算是初学者中的初学者,欢迎交流~
先试试字符串的水。
部分题目是之前考核的时候做的,那时候理解不深,边看题解边写的,现在争取重新做,码风有两种,带快读和万能头的是现在做的。2019.11.24。
旧题已重新过一遍,准备做新题。2019.11.25

  1. kmp的话重点考察对next数组的理解,next[i]是指回滚到上一次匹配的位置,可以发现每次回滚的长度都是 j-next[j] 。所以当有循环节
    (n%(n−next[n])==0 && next[n] != 0)的时候,n-next[n]便是最小的循环节长度,循环次数便是 n / ( n - next[n] ) 。
  2. Manacher主要是理解其求最大回文串的思想。

kuangbin之外:
kmp模板:点击进入新世界
马拉车算法模板:不懂马拉车的可以点这里

1.Number Sequence

原题链接:传送门

思路:

  1. kmp模板题,把字符数组换成数字数组 。

    代码如下:
#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;
ll a[manx],b[manx],nexts[manx];
ll n,m;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || b[i]==b[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
ll kmp()
{
    getnexts();
    int i=0,j=0;
    while(i<n && j<m){
        if( j==-1 || a[i]==b[j] ) ++i,++j;
        else j=nexts[j];
    }
    if(j==m) return i-j+1;
    else return -1;
}
int main()
{
    ll p=read();
    while(p--)
    {
        n=read(),m=read();
        for(int i=0;i<n;i++)   a[i]=read();
        for(int i=0;i<m;i++)   b[i]=read();
        cout<<kmp()<<endl;
    }
    return 0;
}


2.Oulipo

原题链接:传送门

思路:

  1. 模板题。
  2. 匹配完一圈继续回到 next[j] 的位置,见代码注释处。

    代码如下:
#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#define stdd std::ios::sync_with_stdio(false)
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;
ll nexts[manx];
ll n,m,ans,t;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
ll kmp()
{
    getnexts();
    int i=0,j=0,ans=0;
    while(i<n ){
        if( j==-1 || s[i]==p[j] ) ++i,++j;
        else j=nexts[j];
        if(j==m) ans++,j=nexts[j]; // 匹配结束后让j回滚就可以了
    }
    return ans;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>p>>s;
        m=p.size(),n=s.size();
        cout<<kmp()<<endl;
    }
    return 0;
}


3.剪花布条

原题链接:传送门

思路:

  1. 模板题,计算出现次数,这种情况跟上一题差不多,不过要使j匹配结束后回到0的位置,见代码注释处。

    代码如下:
#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#define stdd std::ios::sync_with_stdio(false)
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;
ll nexts[manx];
ll n,m,ans;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
ll kmp()
{
    getnexts();
    int i=0,j=0,ans=0;
    while(i<n && j<m){
        if( j==-1 || s[i]==p[j] ) ++i,++j;
        else j=nexts[j];
        if(j==m) ans++,j=0; //就是这里,匹配结束后要重置j
    }
    return ans;
}
int main()
{
    stdd;
    while(cin>>s)
    {
        if(s[0]=='#') break;
        cin>>p;
        m=p.size(),n=s.size();
        cout<<kmp()<<endl;
    }
    return 0;
}


4.Cyclic Nacklace

原题链接:传送门

思路:

  1. 考察对next数组的理解:周期性字符串循环节长度 ans 是 n−next[n] ,也可以理解为 n-next 的前缀是最小覆盖子串 ,而当前提为n% ans==0&&next[n] !=0时,循环次数是 n/ans 。
  2. 实在不懂可以翻本文章的开头有解析,或者私信,欢迎交流。

    代码如下:
#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e5+5;
ll nexts[manx];
ll n,m,ans,t;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>t;
    while(t--)
    {
        cin>>p;
        m=p.size();
        getnexts();
        ll len=m-nexts[m];
        if(len!=m && m%len==0) cout<<0<<endl;
        else cout<<len-m%len<<endl;
    }
    return 0;
}


5.Count the string

原题链接:传送门

思路:

  1. 这道题是求所以前缀出现的次数和。
  2. 要深刻理解next数组,当i匹配失败的时候会回到next[i]的位置,所以当前串包含了next[i]所包含的前缀数+其当前本身,所以可以得到状态转移方程:
  3. dp[i] = dp[ next[i] ] +1

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=2e5+5;
ll nexts[manx],dp[manx];
ll n,m,ans,t;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>t;
    while(t--)
    {
        cin>>m>>p;
        getnexts();
        ans=0;
        for(int i=1;i<=m;i++)
            dp[i]=(dp[nexts[i]]+1)%10007,ans=(dp[i]+ans)%10007;
        cout<<ans<<endl;
    }
    return 0;
}


6. Simpsons’ Hidden Talents

原题链接:传送门

思路:

  1. 求最大公共s1前缀和s2后缀,可以把两个串连在一起,再用nexts数组来做。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;


ll nexts[manx],m,n;
string s,p;
void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    while(cin>>p)
    {
        cin>>s;
        ll l1=p.size(),l2=s.size();
        p=p+s;
        m=p.size();
        getnexts();
        ll ans=nexts[m];
        while(ans>l1||ans>l2) ans=nexts[ans];
        if(ans==0) cout<<0<<endl;
        else {
            for(int i=0;i<ans;i++) cout<<p[i];
            cout<<" "<<ans<<endl;
        }

    }
    return 0;
}


7.Blue Jeans

原题链接:传送门

思路:

  1. 暴力匹配,取第一个串为模式串,暴力枚举每个子串是否在其他串中出现过。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e4+5;


string s[manx];

int main()
{
    ll t=read();
    while(t--)
    {
        ll  n=read();
        string b="";
        for(int i=0;i<n;i++) cin>>s[i];
        for(int i=0;i<=60;i++)
            for(int j=0;j<60;j++)
            {
                ll flag=1;
                string p=s[0].substr(j,i);
                for(int k=1;k<n;k++)
                    if(s[k].find(p)==string::npos){
                        flag=0;
                        break;
                    }
                if(flag) {
                    if(p.size()>b.size()) b=p;
                    else if(p.size()==b.size()&&p<b) b=p;
                }
            }
        if(b.size()<3) cout<<"no significant commonalities"<<endl;
        else cout<<b<<endl;
    }
    return 0;
}


8.Power Strings

原题链接:传送门

思路:

  1. 考察对next数组的理解:周期性字符串循环节长度 ans 是 n−next[n] ,也可以理解为 n-next 的前缀是最小覆盖子串 ,而当前提为n% ans==0&&next[n] !=0时,循环次数是 n/ans 。
  2. 实在不懂可以翻本文章的开头有解析,或者私信,欢迎交流。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;
ll nexts[manx];
ll n,m,ans,t;
string p,s;

void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    while(cin>>p)
    {
        if(p[0]=='.') break;
        m=p.size();
        getnexts();
        ll len=m-nexts[m];
        if(len!=m && m%len==0 ) cout<<m/len<<endl;
        else cout<<1<<endl;
    }
    return 0;
}


9. 最长回文

原题链接:传送门

思路:

  1. manacher模板题 没什么好说的 。
  2. 回文串:不懂马拉车的可以点这里
  3. 注意取消cin和cout的同步性。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;

string manacher(string s1)
{
    string s="$#";
    for(int i=0;i<s1.size();i++)
        s+=s1[i],s+="#";
    vector<int>p(s.size(),0);
    int id=0,mx=0,maxpoint=0,maxlen=0;
    for(int i=1;i<s.size();i++){
        p[i]=mx>i+p[i]?min(mx-i,p[2*id-i]):1;
        while(s[i+p[i]]==s[i-p[i]]) ++p[i];
        if(i+p[i]>mx) id=i,mx=i+p[i];
        if(p[i]>maxlen) maxlen=p[i],maxpoint=i;
    }
    return s1.substr( (maxpoint-maxlen)/2 , maxlen-1) ;
}

int main()
{
    string s;
    std::ios::sync_with_stdio(false);
    while(cin>>s)
    {
        s=manacher(s);
        cout<<s.size()<<endl;
    }
    return 0;
}


10. Girls’ research

原题链接:传送门

思路:

  1. Manacher模板题 。
  2. 回文串:不懂马拉车的可以点这里
  3. s1.substr( (maxpoint-maxlen)/2, maxlen-1) 是截取最大回文串,那么 (maxpoint-maxlen)/2 就是回文串的起始位置 , 长度为maxlen-1 ,那么可以知道结束位置=起始位置+长度-1=(maxpoint-maxlen)/2+maxlen-2。
  4. 注意取消cin和cout的同步性。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;

void manacher(string s1)
{
    string s="$#";
    for(int i=0;i<s1.size();i++)
        s+=s1[i],s+="#";
    vector<int>p(s.size(),0);
    int id=0,mx=0,maxpoint=0,maxlen=0;
    for(int i=1;i<s.size();i++){
        p[i]=mx>i+p[i]?min(mx-i,p[2*id-i]):1;
        while(s[i+p[i]]==s[i-p[i]]) ++p[i];
        if(i+p[i]>mx) id=i,mx=i+p[i];
        if(p[i]>maxlen) maxlen=p[i],maxpoint=i;
    }
    if(maxlen>3){
        cout<<(maxpoint-maxlen)/2<<" "<<(maxpoint-maxlen)/2+maxlen-2<<endl;
        cout<<s1.substr( (maxpoint-maxlen)/2 , maxlen-1)<<endl;
    }
    else puts("No solution!");
}

int main()
{
    string s;
    char c;
    int ans;
    std::ios::sync_with_stdio(false);
    while(cin>>c>>s)
    {
        ans=c-'a';
        for(int i=0;i<s.size();i++)
            if(s[i]>=c) s[i]=s[i]-ans;
            else s[i]=s[i]+26-ans;
        manacher(s);
    }
    return 0;
}



11. Palindrome

原题链接:传送门

思路:

  1. Manacher模板题 ,跟模板一模一样,不懂的可以点下面这个。
  2. 回文串:不懂马拉车的可以点这里

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;

string manacher(string s1)
{
    string s="$#";
    for(int i=0;i<s1.size();i++)
        s+=s1[i],s+="#";
    vector<int>p(s.size(),0);
    int id=0,mx=0,maxpoint=0,maxlen=0;
    for(int i=1;i<s.size();i++){
        p[i]=mx>i+p[i]?min(mx-i,p[2*id-i]):1;
        while(s[i+p[i]]==s[i-p[i]]) ++p[i];
        if(i+p[i]>mx) id=i,mx=i+p[i];
        if(p[i]>maxlen) maxlen=p[i],maxpoint=i;
    }
    return s1.substr( (maxpoint-maxlen)/2 , maxlen-1) ;
}

int main()
{
    int t=1;
    string s;
    while(cin>>s)
    {
        if(s=="END") break;
        s=manacher(s);
        cout<<"Case "<<t++<<": "<<s.size()<<endl;
    }
    return 0;
}


12. Theme Section

原题链接:传送门

思路:

  1. kmp思维题,由next数组可得nexts[m]为最长的公共前后缀,再暴力枚举即可。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e7+5;


ll nexts[manx];
string s,p;
ll n,m;
void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    ll t=read();
    while(t--)
    {
        cin>>p;
        m=p.size();
        getnexts();
        int len=nexts[m];
        while(len*3>m) len--;
        while(len)
        {
            string s1=p.substr(0,len),s2=p.substr(len,m-2*len);
            if(s2.find(s1)==string::npos) len--;
            else break;
        }
        cout<<len<<endl;
    }
    return 0;
}


13. 吉哥系列故事——完美队形II

原题链接:传送门

思路:

  1. manacher模板题 。
  2. 回文串:不懂马拉车的可以点这里
  3. 注意s[i-p[i]]<=s[i-p[i]+2] 保持队列左边递增,这样回文对称右边就递减了。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;
ll a[manx],n;

ll manacher()
{
    vector<ll>s;
    s.push_back(-1);
    s.push_back(0);
    for(int i=0;i<n;i++)
        s.push_back(a[i]),s.push_back(0);
    vector<int>p(s.size(),0);
    int id=0,mx=0,maxpoint=0,maxlen=0;
    for(int i=1;i<s.size();i++){
        p[i]=mx>i+p[i]?min(mx-i,p[2*id-i]):1;
        while(s[i+p[i]]==s[i-p[i]]&&s[i-p[i]]<=s[i-p[i]+2]) ++p[i];
        if(i+p[i]>mx) id=i,mx=i+p[i];
        if(p[i]>maxlen) maxlen=p[i],maxpoint=i;
    }
    return maxlen-1;
}

int main()
{
    ll t=read();
    while(t--)
    {
        n=read();
        for(int i=0;i<n;i++) a[i]=read();
        cout<<manacher()<<endl;
    }
    return 0;
}



14. Substrings

原题链接:传送门

思路:

  1. 跟第七题类似,可以参考一下第七题的思路,不过多了一个反转串的判断。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e4+5;


string s[manx];

int main()
{
    ll t=read();
    while(t--)
    {
        ll  n=read(),ans=0;
        for(int i=0;i<n;i++) cin>>s[i];
        for(int i=0;i<=s[0].size();i++)
            for(int j=0;j<s[0].size();j++)
            {
                ll flag=1;
                string p=s[0].substr(j,i);
                string t=p;
                reverse(p.begin(),p.end());
                for(int k=1;k<n;k++)
                    if(s[k].find(p)==string::npos&&s[k].find(t)==string::npos){
                        flag=0;
                        break;
                    }
                ll res=max(p.size(),t.size());
                if(flag) ans=ans>res?ans:res;
            }
        cout<<ans<<endl;
    }
    return 0;
}


15. Wow! Such Doge!

原题链接:传送门

思路:

  1. 水题,暴力枚举判断即可。

    代码如下:
//#include<bits/stdc++.h>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e7+5;


int main()
{
    string s;
    ll ans=0;
    while(cin>>s)
    {
        for(int i=0;i<s.size();i++)
            if(s[i]=='D'||s[i]=='d')
                if(s[i+1]=='o'||s[i+1]=='O')
                    if(s[i+2]=='g'||s[i+2]=='G')
                        if(s[i+3]=='e'||s[i+3]=='E')
                            ans++;
    }
    cout<<ans<<endl;
    return 0;
}


16. Period

原题链接:传送门

思路:

  1. 考察next数组,由于next数组的储存原理,需要从下标等于2开始枚举。

    代码如下:
//#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#include<string>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;


ll nexts[manx];
ll n,m;
string p;
void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    int n=1;
    while(scanf("%64d",&m)!=EOF)
    {
        if(m==0) break;
        cin>>p;
        getnexts();
        printf("Test case #%d\n",n++);
        for(int i=2;i<=m;i++)
            if( i%(i-nexts[i])==0 && i/(i-nexts[i])>1 )
                printf("%d %d\n",i,i/(i-nexts[i]));
        printf("\n");
    }
    return 0;
}


17. Seek the Name, Seek the Fame

原题链接:传送门

思路:

  1. 考察next数组,next[i]表示最大的前后缀相同长度,所以从最后面开始枚举。

    代码如下:
//#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#include<string>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e6+5;


ll nexts[manx];
ll n,m;
string p;
void getnexts()
{
    int i=0,j=-1;
    nexts[i]=j;
    while(i<m){
        if(j==-1 || p[i]==p[j]) nexts[++i]=++j;
        else j=nexts[j];
    }
}
int main()
{
    while(cin>>p)
    {
        m=p.size();
        getnexts();
        vector<ll>ans;
        ans.clear();
        while(m>0){
            ans.push_back(m);
            m=nexts[m];
        }
        for(int i=ans.size()-1;i>=0;i--)
            cout<<ans[i]<<" ";
        cout<<endl;
    }
    return 0;
}


18. Corporate Identity

原题链接:传送门

思路:

  1. 跟第七题类似,暴力枚举即可。

    代码如下:
//#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#include<string>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }

const int manx=1e4+5;


string s[manx];
int main()
{
    IOS;
    int n;
    while(cin>>n&&n)
    {
        string ans="";
        for(int i=0;i<n;i++) cin>>s[i];
        for(int i=0;i<=s[0].size();i++)
            for(int j=0;j<s[0].size();j++)
            {
                ll flag=1;
                string p=s[0].substr(j,i);
                for(int k=1;k<n;k++)
                {
                    if(s[k].find(p)==string::npos)
                    {
                        flag=0;
                        break;
                    }
                }
                if(flag){
                    if(p.size()>ans.size()) ans=p;
                    else if(p.size()==ans.size()&&ans>p) ans=p;
                }
            }
        if(ans.size()>0) cout<<ans<<endl;
        else cout<<"IDENTITY LOST"<<endl;
    }
    return 0;
}



发布了50 篇原创文章 · 获赞 15 · 访问量 4234

猜你喜欢

转载自blog.csdn.net/JiangHxin/article/details/102255284