P3426 [POI2005]SZA-Template

P3426 [POI2005]SZA-Template

链接

分析:

  首先T一定是S的一个前缀,也是一个后缀。

  判断一个前缀s[1...i]是不是满足条件,那么求出s[1...i]在s中出现的所有位置,如果相邻的两个位置之间的距离的最大值小于等于i,那么就是满足的。

  于是可以建出fail树,每次从根到n走,那么出现的位置的个数是递减的,于是链表维护即可。

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 1000005;
int p[N], L[N], R[N], to[N], mx;
vector<int> T[N];
char s[N];

void del(int x) {
    if (x) {
        int a = L[x], b = R[x];
        mx = max(mx, b - a);
        L[b] = a, R[a] = b;
    }
    for (auto v : T[x]) if (v != to[x]) del(v);
}
int main() {
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    p[1] = 0;
    for (int j = 0, i = 2; i <= n; ++i) {
        while (j && s[j + 1] != s[i]) j = p[j];
        if (s[j + 1] == s[i]) j ++;
        p[i] = j;
    }
    for (int i = 1; i <= n; ++i) T[p[i]].push_back(i);
    for (int i = n; i; i = p[i]) to[p[i]] = i;
    for (int i = 1; i <= n; ++i) L[i] = i - 1, R[i] = i + 1;
    int now = 1;
    del(0);
    while (now < mx) { del(now), now = to[now]; }
    cout << now;
    return 0;
}

 

 

posted @ 2019-03-25 17:50  MJT12044  阅读(285)  评论(0编辑  收藏  举报