[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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章