Kyoto University Programming Contest 2016 G题Exam(后缀数组)
题意
有一个字符串集合S和字符串T,满足以下条件:
- S中任意字符串都是T的一个连续子串
- 在S中每一对不同的字符串x,y,x不为y的子串。
给出T,求S集合中可能的最大字符串数目。
数据范围
\[1\leq |T|\leq 10^5
\]
|T|表示字符串T的长度。
题解
假设当前\(S\)集合中有\(x\)个字符串,每一个对应T的\([l_i,r_i]\),因为题目要求每一个字符串不为另一字符串的子串,可以推断出:将S中所有字符串按照\(l_i\)排序一定有\(l_1<l_2<...<l_x\)且\(r_1<r_2<...<r_x\)。假设当前的所有后缀最长公共前缀为LCP,对于每一个字符串取区间\([i,i+LCP](1\leq i\leq n-LCP)\),此时,集合中每一个字符串长度相等,两个长度相等的字符串要不为子串关系,即为不相等。因为当前每一个字符串都是后缀字符串的一个前缀,且长度为LCP+1,故这么取出来的所有字符串一定不会相等,数目有\(n-LCP\)个。
我们假设从x起始的后缀字符串与从y起始的后缀字符串最长公共前缀为LCP,则若x,y都作为左端点加入集合时,其长度一定要大于LCP,对于一个区间长度为LCP+1的字符串\([i,i+LCP]\),要保证后面所有字符串不相互包含,要么大于x的位置作为左端点时区间长度都要大于LCP,要么[i+1,i+LCP]都不作为左端点。前者一定会牺牲最后LCP个位置作为左端点,后者也少了LCP个位置当左端点,所以总数目不会超过\(n-LCP\)。若x,y不全加入集合,则能作为左端点的位置-1,此时所有后缀的最长公共前缀为LCP-1,此时又是一个新的状态,以此递推,最终数目也不会超过\(n-LCP\)。
代码
/*************************************************************************
> File Name: 2.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https: https://www.cnblogs.com/Knowledge-Pig/
> Created Time: 2021/1/29 15:05:35
************************************************************************/
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e5+10;
char s[maxx];
int n,m,x[maxx],y[maxx],sa[maxx],rk[maxx],height[maxx],c[maxx],x_new[maxx];
void get_sa(){
For(i,1,n) ++c[x[i]=s[i]];
For(i,2,m) c[i]+=c[i-1];
for(int i=n;i>=1;--i) sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int num=0;
For(j,n-k+1,n) y[++num]=j;
For(j,1,n) if(sa[j]>k) y[++num]=sa[j]-k;
For(j,1,m) c[j]=0;
For(j,1,n) ++c[x[j]];
For(j,2,m) c[j]+=c[j-1];
for(int j=n;j>=1;--j) sa[c[x[y[j]]]--]=y[j];
x_new[sa[1]]=1; num=1;
for(int j=2;j<=n;++j)
x_new[sa[j]]=(x[sa[j]]==x[sa[j-1]] && x[sa[j]+k]==x[sa[j-1]+k]) ? num : ++num;
for(int j=1;j<=n;++j) x[j]=x_new[j];
if(num==n) break;
m=num;
}
}
void get_height(){
int k=0;
For(i,1,n) rk[sa[i]]=i;
For(i,1,n){
if(rk[i]==1) continue;
if(k>0) --k;
int j=sa[rk[i]-1];
while(i+k<=n && j+k<=n && s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
scanf("%s",s+1);
n=strlen(s+1); m=122;
get_sa();
get_height();
int ans=0;
For(i,2,n) ans=max(ans,height[i]);
printf("%d\n",n-ans);
return 0;
}

浙公网安备 33010602011771号