bzoj 4310 跳蚤

后缀数组+二分

1.

从后往前贪心扫

当必须分的时候就分一段

注意比较两个串大小时的细节

2.

先二分这个串第一次出现时在后缀数组上的位置

再二分具体是哪个串

从前往后扫,使右端点不断往左缩,当 右<=左 时分一段

快的飞起

1.

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define ll long long
using namespace std;
char s[N];
int rk[N],sa[N],wb[N],sum[N];
void sasa(int n,int m)
{
    int *x=rk,*y=wb;
    for(int i=0;i<m;i++)sum[i]=0;
    for(int i=0;i<n;i++)sum[x[i]=s[i]]++;
    for(int i=1;i<m;i++)sum[i]+=sum[i-1];
    for(int i=n-1;i>=0;i--)sa[--sum[x[i]]]=i;
    for(int j=1,p=1;p<n;m=p,j<<=1)
    {
        p=0;
        for(int i=n-j;i<n;i++)y[p++]=i;
        for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(int i=0;i<m;i++)sum[i]=0;
        for(int i=0;i<n;i++)sum[x[i]]++;
        for(int i=1;i<m;i++)sum[i]+=sum[i-1];
        for(int i=n-1;i>0;i--)sa[--sum[x[y[i]]]]=y[i];
        swap(x,y);x[sa[0]]=0;p=1;
        for(int i=1;i<n;i++)
            x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
    }
    return ;
}
int h[N];
void calh(int n)
{
    for(int i=1;i<=n;i++)rk[sa[i]]=i;
    int k=0;
    for(int i=0;i<n;i++)
    {
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[j+k]==s[i+k])k++;
        h[rk[i]]=k;
    }
    return ;
}
int mn[N][20],lg[N],n;
void ST()
{
    lg[0]=-1;
    for(int i=1;i<=100000;i++)lg[i]=lg[i>>1]+1;
    for(int i=1;i<=n;i++)mn[i][0]=h[i];
    for(int i=1;i<20;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(j+(1<<(i-1))<=n)
            {
                mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
            }
            else mn[j][i]=mn[j][i-1];
        }
    }return ;
}
int qur(int l,int r)
{
    int k=lg[r-l+1];
    return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
bool cmp(int x,int len1,int y,int len2)
{
    if(x<y)
    {
        int p=qur(x+1,y);
        if(p>=len2&&p<len1)return 0;
        return 1;
    }
    else if(x>y)
    {
        int p=qur(y+1,x);
        if(p>=len1)return 1;
        return 0;
    }
    else
    {
        if(len1<=len2)return 1;
        return 0;
    }
}
int k;
bool pan(ll x)
{
    int now=1;ll tot=0;
    int pos,len;
    for(int i=1;i<=n;i++)
    {
        ll pre=tot;
        tot+=n-sa[i]-h[i];
        if(tot>=x)
        {
            pos=i;len=h[i]+x-pre;
            break;
        }
    }
    int ta=n-1;
    for(int i=n-1;i>=0;i--)
    {
        if(!cmp(rk[i],1,pos,len))return 0;
        if(!cmp(rk[i],ta-i+1,pos,len))
        {
            ta=i,now++;
        }
    }
    return now<=k;
}
int main()
{
    scanf("%d",&k);
    scanf("%s",s);
    n=strlen(s);
    sasa(n+1,256);
    calh(n);
    ST();
    ll sm=1LL*n*(n+1)/2;
    for(int i=1;i<=n;i++)sm-=h[i];
    ll l=1,r=sm;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(pan(mid))r=mid;
        else l=mid+1;
    }
    ll tot=0;
    int pos,len;
    for(int i=1;i<=n;i++)
    {
        ll pre=tot;
        tot+=n-sa[i]-h[i];
        if(tot>=l)
        {
            pos=i;len=h[i]+l-pre;
            break;
        }
    }
    for(int i=0;i<len;i++)
    {
        putchar(s[sa[pos]+i]);
    }puts("");
    return 0;
}

2.

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
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
char s[N];
int c[N],sa[N],m,n,rk[N],t1[N],t2[N],v[N];
void saa(char *s,int n,int m)
{
    int *x=t1,*y=t2;
    for(int i=0;i<m;i++)c[i]=0;
    for(int i=0;i<n;i++)c[x[i]=s[i]]++;
    for(int i=1;i<m;i++)c[i]+=c[i-1];
    for(int i=0;i<n;i++)sa[--c[x[i]]]=i;
    int p=1;
    for(int j=1;p<n;j<<=1,m=p)
    {
        p=0;
        for(int i=n-j;i<n;i++)y[p++]=i;
        for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(int j=0;j<m;j++)c[j]=0;
        for(int i=0;i<n;i++)c[x[i]]++;
        for(int j=1;j<m;j++)c[j]+=c[j-1];
        for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);x[sa[0]]=0;p=1;
        for(int i=1;i<n;i++)
          x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
    }
    return ;
}
int h[N];
void calh(int n)
{
    for(int i=1;i<=n;i++)rk[sa[i]]=i;
    int k=0;
    for(int i=0;i<n;i++)
    {
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        h[rk[i]]=k;
    }
    return ;
}
int main()
{
    scanf("%d %s",&m,s);
    n=strlen(s);s[n]=0;
    saa(s,n+1,300);
    calh(n);
    int l=1,r=n;
    while(l<r)
    {
        int mid=(l+r)>>1,num=0,mn=n,m1=n;
        for(int i=mid+1;i<=n;i++){m1=min(m1,h[i]);v[sa[i]]=m1;if(!h[i])num=m+1;}
        for(int i=0;i<=n-1;i++)
        {
            if(mn==i)num++,mn=n;
            if(v[i])mn=min(mn,i+v[i]);
        }
        if(num+1<=m)r=mid;else l=mid+1;
        for(int i=mid+1;i<=n;i++)v[sa[i]]=0;
    }
    int u=l;
    l=h[u]+1,r=n-sa[u];    
    while(l<r)
    {
         int mid=(l+r)>>1,k=u,num=0,mn=n,m1=mid;
         for(int i=u+1;i<=n;i++){m1=min(m1,h[i]);v[sa[i]]=m1;}
         v[sa[u]]=mid;
         for(int i=0;i<n;i++)
         {
            if(mn==i)num++,mn=n;
            if(v[i])mn=min(mn,i+v[i]);
         }
         if(num+1<=m)r=mid;else l=mid+1;
         for(int i=k;i<=u;i++)v[sa[i]]=0;
    }
    for(int i=1;i<=l;i++)printf("%c",s[sa[u]+i-1]);
    puts("");
    return 0;
}

  

posted @   SD_le  阅读(255)  评论(0编辑  收藏  举报
重置按钮
点击右上角即可分享
微信分享提示