1. 程式人生 > >POJ2752 Seek the Name, Seek the Fame

POJ2752 Seek the Name, Seek the Fame

inline [1] read pri std str print deque vector

題意

給定一個字符串s,從小到大輸出s中既是前綴又是後綴的子串的長度。

$1 \leq |s| \leq 400000 $

分析

一道kmp裸題。

設串長為n,且base 0。算出kmp失配指針後,n為最長長度,然後用fail數組往前跳即為答案,因為根據fail數組的含義,f[i]意為找到最長前綴(~f[i]-1)與後綴(~i-1)匹配,然後又因為base 0,所以數組的值都不用加1.要從小到大輸出,所以用棧存儲。

代碼

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch==‘-‘)
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-‘0‘,ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

char s[400010];
int f[400010];

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    while(~scanf("%s",s))
    {
        int n=strlen(s);
        f[0]=f[1]=0;
        for(int i=1;i<=n;++i)
        {
            int j=f[i];
            while(j&&s[j]!=s[i])
            j=f[j];
            f[i+1]=s[i]==s[j]?j+1:0;
        }
        stack<int>S;
        int x=n;
        while(x)
        {
            S.push(x);
            x=f[x];
        }
        while(!S.empty())
        {
            printf("%d ",S.top());
            S.pop();
        }
        printf("\n");
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

POJ2752 Seek the Name, Seek the Fame