CF700E Cool Slogans 题解

考虑转化题意,容易发现我们一定可以找到一个\(k\)最大的\(s\)序列使得\(s_{i-1}\)\(s_i\)\(boder\)。然后建立后缀自动机,每一个父节点是它的后缀,然后维护一条链,考虑能多出一个\(s_i\)就多出一个\(s_i\)(省流:贪心),然后每个点维护\(k\)最大时节点的最小的位置,考虑我们要判断一个区间是否出现,我们发现可以直接用\(endpos\)集合,假设\(i\)\(j\)的祖先,\(pos_j\)\(j\)\(endpos\)集合中的一个值,那么\(i\)\(endpos\)集合中一定含有\(pos_j\),只需要判断\([pos_j-len_j+len_{i},pos_j-1]\)中有没有出现的\(endpos\)值就可以了,容易发现对于一个节点,\(i\)一定是它祖先中最后一个被更新答案的节点。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=8e5+10;
struct edge{
	map<int,int>ch;
	int link;
	int pos;
	int len;
	int rt;
}tree[maxn];
struct node{
	int ls;
	int rs;
}t[maxn<<5];
int lst,n,f[maxn],tot=1,idd,ans,top[maxn],lin,pos[maxn],nn;
vector<int>tu[maxn];
string s;
void insert(int c){
	int p=lst,np,q,nq;
	tot++;
	np=tot;
	pos[np]=nn;
	tree[np].len=tree[p].len+1;
	for(;p&&!tree[p].ch[c];p=tree[p].link){
		tree[p].ch[c]=np;
	}
	if(!p){
		tree[np].link=1;
	}
	else{
		q=tree[p].ch[c];
		if(tree[p].len+1==tree[q].len){
			tree[np].link=q;
		}
		else{
			tot++;
			nq=tot;
			tree[nq]=tree[q];
			pos[nq]=pos[q];
			tree[nq].len=tree[p].len+1;
			tree[q].link=nq;
			tree[np].link=nq;
			for(;p&&tree[p].ch[c]==q;p=tree[p].link){
				tree[p].ch[c]=nq;
			}
		}
	}
	lst=np;
	return;
}
void add(int &id,int l,int r,int q){
	if(!id){
		idd++;
		id=idd;
	}
	if(l==r){
		return;
	}
	int mid=(l+r)/2;
	if(q<=mid){
		add(t[id].ls,l,mid,q);
	}
	else{
		add(t[id].rs,mid+1,r,q);
	}
	return;
}
int merge(int q,int w){
	if(!q||!w){
		return q+w;
	}
	idd++;
	int zhi=idd;
	t[zhi].ls=merge(t[q].ls,t[w].ls);
	t[zhi].rs=merge(t[q].rs,t[w].rs);
	return zhi;
}
bool query(int id,int l,int r,int q,int w){
	if(!id){
		return 0;
	}
	if(q<=l&&r<=w){
		return 1;
	}
	int mid=(l+r)/2;
	if(q<=mid&&query(t[id].ls,l,mid,q,w)){
		return 1;
	}
	if(w>mid&&query(t[id].rs,mid+1,r,q,w)){
		return 1;
	}
	return 0;
}
void dfs1(int q){
	for(int i=0;i<(int)tu[q].size();i++){
		dfs1(tu[q][i]);
		tree[q].rt=merge(tree[q].rt,tree[tu[q][i]].rt);
	}
	return;
}
void dfs(int q){
	if(tree[q].link==1){
		f[q]=1;
		top[q]=q;
	}
	else{
		int p=pos[q];
		lin=query(tree[top[tree[q].link]].rt,1,n,p-tree[q].len+tree[top[tree[q].link]].len,p-1);
		if(lin){
			f[q]=f[tree[q].link]+1;
			top[q]=q;
		}
		else{
			f[q]=f[tree[q].link];
			top[q]=top[tree[q].link];
		}
	}
	for(int i=0;i<(int)tu[q].size();i++){
		dfs(tu[q][i]);
	}
	ans=max(ans,f[q]);
	return;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>s;
	lst=1;
	for(int i=0;i<(int)s.size();i++){
		nn=i+1;
		insert(s[i]-'a');
		add(tree[lst].rt,1,n,nn);
	}
	for(int i=2;i<=tot;i++){
		tu[tree[i].link].push_back(i);
	}
	dfs1(1);
	for(int i=0;i<(int)tu[1].size();i++){
		dfs(tu[1][i]);
	}
	cout<<ans;
	return 0;
}
posted @ 2025-05-19 10:23  特别之处  阅读(8)  评论(0)    收藏  举报