BZOJ4516: [Sdoi2016]生成魔咒

果然SA比SAM+map快。

首先这是SAM裸题,然而SA求本质不同子串个数也很容易。考虑倒着建SA,这样没错加一个字符就变成加一个后缀,其他后缀都不变,那么i的答案就是只考虑前i个后缀的答案。搞个双向链表,每次删一个后缀并RMQ更新答案。

(SAM+map复杂度可能是错的,但是我不清楚)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<algorithm>
#include<cstdio>
#define lb lower_bound
using namespace std;
const int N=1e5+5;
typedef int arr[N];
arr sa,r,f[17],c,v,s,t,p,q;
typedef long long ll;
ll b,z[N];
void pre(int*s,int n){
    for(int i=0;i<n;++i)
        ++c[s[i]];
    for(int i=1;i<n;++i)
        c[i]+=c[i-1];
    for(int i=n-1;~i;--i)
        sa[--c[s[i]]]=i;
    int m=0;
    for(int i=1;i<n;++i)
        r[sa[i]]=s[sa[i]]!=s[sa[i-1]]?++m:m;
    for(int j=1;;j<<=1){
        if(++m==n)break;
        for(int i=0;i<j;++i)
            v[i]=n-j+i;
        for(int i=0;i<m;++i)
            c[i]=0;
        for(int i=0,k=j;i<n;++i){
            if(sa[i]>=j)
                v[k++]=sa[i]-j;
            ++c[r[i]];
        }
        for(int i=1;i<m;++i)
            c[i]+=c[i-1];
        for(int i=n-1;~i;--i)
            sa[--c[r[v[i]]]]=v[i],v[i]=r[i];
        m=r[sa[0]]=0;
        for(int i=1;i<n;++i)
            r[sa[i]]=v[sa[i]]!=v[sa[i-1]]||v[sa[i]+j]!=v[sa[i-1]+j]?++m:m;
    }
}
int ask(int i,int j){
    int k=__lg(j-i+1);
    return min(f[k][i],f[k][j-(1<<k)+1]);
}
struct buf{
    char z[9<<17],*s;
    buf():s(z){
        z[fread(z,1,sizeof z,stdin)]=0;
    }
    operator int(){
        int x=0;
        while(*s<48)++s;
        while(*s>32)
            x=x*10+*s++-48;
        return x;
    }
}it;
int main(){
    int n=it;
    for(int i=n-1;~i;--i)
        s[i]=t[i]=it;
    sort(t,t+n);
    for(int i=0;i<n;++i)
        s[i]=lb(t,t+n,s[i])-t+1;
    pre(s,n+1);
    for(int i=0,j=0;i<n;++i){
        if(j)--j;
        while(s[i+j]==s[sa[r[i]-1]+j])++j;
        f[0][r[i]]=j;
    }
    for(int j=1;n>>j;++j)
        for(int i=0;i+(1<<j)-1<=n;++i)
            f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
    for(int i=1;i<=n;++i)
        b+=n-sa[i]-f[0][i];
    for(int i=n;i>1;--i)
        p[i]=i-1;
    for(int i=1;i<n;++i)
        q[i]=i+1;
    for(int i=0;i<n;++i){
        int j=r[i],k=0;
        if(p[j])k=max(k,ask(p[j]+1,j));
        if(q[j])k=max(k,ask(j+1,q[j]));
        z[i]=b,b-=n-i-k;
        p[q[j]]=p[j];
        q[p[j]]=q[j];
    }
    for(int i=n-1;~i;--i)
        printf("%lld\n",z[i]);
}
posted @   f321dd  阅读(333)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示