1. 程式人生 > >Codeforces 126B. Password(KMP,DP)

Codeforces 126B. Password(KMP,DP)

Codeforces 126B. Password

題意:一個字串,找出最長的子串t,它既是字首又是字尾,還出現在中間。輸出t,不存在則輸出Just a legend。
思路:利用KMP演算法處理出next陣列,由next陣列的意義可以知道i為尾的最長相同字首字尾。則ne[n-1],ne[ne[n-1]],ne[ne[ne[n-1]]]......均為可能的解,且長度遞減,為了高效的逐一驗證,則需要預處理出整個字串有多少個與該字首相同的子串。用到DP思想,cnt[next[i]]+=cnt[i],倒著更新一遍,即可處理出上述資訊。那麼cnt大等於3的字首,均為可行解
程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#define dd(x) cout<<#x<<" = "<<x<<" "
#define de(x) cout<<#x<<" = "<<x<<"\n"
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn=1e6+10,mod=1e9+7,INF=0x3f3f3f3f;
char s[maxn];
int ne[maxn],cnt[maxn];
void init()
{
    ne[0]=-1;
    for (int i=1;s[i];++i)
    {
        int j=ne[i-1];
        while (s[j+1]!=s[i]&&j>=0)
            j=ne[j];
        if (s[j+1]==s[i])
            ne[i]=j+1;
        else
            ne[i]=-1;
    }
}
int main()
{
    scanf("%s",s);
    init();
    int n=strlen(s);
    for (int i=0;i<n;++i)
        cnt[i]=1;
    for (int i=n-1;i;--i)
        cnt[ne[i]]+=cnt[i];
    for (int i=ne[n-1];i!=-1;i=ne[i])
    {
        if (cnt[i]>=3)
        {
            for (int j=0;j<=i;++j)
                printf("%c",s[j]);
            return 0;
        }
    }
    printf("Just a legend");
    return 0;
}