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
",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13635212.html