CF700E. Cool Slogans
题目大意
题解
不难但是因为字符串太菜所以想了很久
排行榜上跑得快的一些做法假了,不知道有没有更简单的做法
结论:存在一种最优序列,使得Si是Si-1的后缀,证明把任意一种最优的不断删掉末尾将其顶住
也可以同时满足开头但是不需要,这样可以写个O(n^2)KMP暴力来拍
把SAM建出来,同一个点上的串两两之间不能放一起,维护f[i][0/1]表示到点i时最长序列的结尾点以及长度,显然按照贪心解是最优的,问题就是快速判断一个串是否在另一个串中出现>=2次
设|A|<|B|,那么随便找B的一个right设为x,A在[x-|B|+|A|,x]中的right个数就是出现次数
如果全部维护不好搞(也许可以线段树合并),那么把right按顺序加入,每个点在最小的right处计算
因为是后缀关系,所以只需要在前面找到最大的right即可,线段树维护+判断
时间复杂度O(nlogn)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
//#define file
using namespace std;
int tr[1600011],A[200001],a[400011][2],ls[400011],Tr[400011][26],fa[400011],bg[400011],ed[400011],Len[400011];
int f[400011][2],sum[400011],n,I,i,j,k,l,len,len2,ans;
bool bz[400011];
char st[200001];
void copy(int t1,int t2) {memcpy(Tr[t1],Tr[t2],sizeof(Tr[t1]));}
void New(int t,int x) {++len;if (Tr[t][x]) copy(len,Tr[t][x]);Tr[t][x]=len,Len[len]=Len[t]+1;}
void NEW(int x,int y) {++len2;a[len2][0]=y;a[len2][1]=ls[x];ls[x]=len2;}
void build()
{
len=1;l=1;
fo(i,1,n)
{
New(l,st[i]-'a'),A[i]=len;
j=fa[l];
while (j && !Tr[j][st[i]-'a']) Tr[j][st[i]-'a']=len,j=fa[j];
if (!j) fa[len]=1;
else
if (Len[j]+1==Len[Tr[j][st[i]-'a']]) fa[len]=Tr[j][st[i]-'a'];
else
{
k=Tr[j][st[i]-'a'],New(j,st[i]-'a');
fa[len]=fa[k],fa[len-1]=len,fa[k]=len;
j=fa[j];
while (j && Tr[j][st[i]-'a']==k) Tr[j][st[i]-'a']=len,j=fa[j];
}
l=Tr[l][st[i]-'a'];
}
}
void dfs(int t)
{
int i;
bg[t]=++j;
for (i=ls[t]; i; i=a[i][1]) dfs(a[i][0]);
ed[t]=j;
}
void change(int t,int l,int r,int x,int s)
{
int mid=(l+r)/2;
tr[t]=max(tr[t],s);
if (l==r) return;
if (x<=mid) change(t*2,l,mid,x,s);
else change(t*2+1,mid+1,r,x,s);
}
int find(int t,int l,int r,int x,int y)
{
int mid=(l+r)/2,ans=0,s;
if (x<=l && r<=y) return tr[t];
if (x<=mid) s=find(t*2,l,mid,x,y),ans=max(ans,s);
if (mid<y) s=find(t*2+1,mid+1,r,x,y),ans=max(ans,s);
return ans;
}
void dg(int t)
{
int i,j,k,l;
if (bz[t]) return;
bz[t]=1;
if (fa[t]==1) f[t][0]=t,f[t][1]=sum[t]=1;
else
{
dg(fa[t]);
j=find(1,1,len,bg[f[fa[t]][0]],ed[f[fa[t]][0]]);
if (I-j+f[fa[t]][1]<=Len[t]) f[t][0]=t,f[t][1]=max(I-j+f[fa[t]][1],Len[fa[t]]+1),sum[t]=sum[fa[t]]+1;
else f[t][0]=f[fa[t]][0],f[t][1]=f[fa[t]][1],sum[t]=sum[fa[t]];
}
}
void work()
{
fo(I,1,n) dg(A[I]),change(1,1,len,bg[A[I]],I);
fo(i,1,len) ans=max(ans,sum[i]);
}
int main()
{
#ifdef file
freopen("CF700E.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%d",&n);
scanf("%s",st+1);
build();
j=0;fo(i,2,len) NEW(fa[i],i); dfs(1);
work();
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}