CF1483F

Posted chasedeath

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1483F相关的知识,希望对你有一定的参考价值。

CF1483F - Exam

题目大意

给定\\(n\\)个不同串\\(s_i\\),令\\(s_i\\sub s_j\\)表示\\(s_i\\)\\(s_j\\)的子串

求所有二元组\\((i,j)(i\\ne j)\\)满足

\\(s_i\\sub s_j,\\nexists k\\ne i,k\\ne j,s_i\\sub s_k\\sub s_j\\)


分析

首先可以说明答案是\\(O(\\sum |s_i|)\\)级别的

对于每个\\(s_j\\)考虑其枚举\\(r\\)作为\\(s_i\\)的右端点,则\\(s_i\\)只有最长的一个会贡献答案

故每个右端点最多对应一个\\(s_i\\)

一般情况下,判断子串相同的问题我们需要\\(\\text{SAM}\\)

但是鉴于这道题实际上需要判别的子串只有\\(n\\)个,而维护匹配只需要\\(\\text{AC}\\)自动机,所以不需要\\(\\text{SAM}\\)

那么可以在\\(\\text{AC}\\)自动机上预处理每个匹配节点在\\(\\text{fail}\\)树上最近的有效祖先

即对于每个右端点找到了最长的\\(s_i\\)

可以对于找到的\\(s_i\\)简单去重,但是仍然存在以下多余计算

1.\\(s_i\\)所对应的\\([l,r]\\)被某一个\\(s_i\'\\)对应的\\([l\',r\']\\)包含的情况,可以\\(O(n)\\)判断区间包含干掉

2.一个\\(s_i\\)在这个位置被计算,但是实际上在其他位置被包含

实际上,这只需要判断\\(s_i\\)每一次被出现是否都是有效的即可

可以用树状数组+\\(\\text{dfs}\\)序维护\\(s_i\\)出现的次数

时间复杂度为\\(O((\\sum |s_i|)\\log (\\sum |s_i|))\\),空间复杂度为\\(O((\\sum |s_i|)|\\Sigma|)\\)

似乎是Codeforces上最快的Submission?

const int N=1e6+10,INF=1e9+10;

int n;
int fail[N],lst[N],trie[N][26],End[N],dep[N],fa[N],L[N],R[N],I[N],dfn,cnt;
struct Edge{
	int to,nxt;
} e[N<<1];
int head[N],ecnt;
void AddEdge(int u,int v) {
	e[++ecnt]=(Edge){v,head[u]};
	head[u]=ecnt;
}

void dfs(int u) {
	I[L[u]=++dfn]=u;
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].to;
		if(!lst[v]) lst[v]=lst[u];
		dfs(v);
	}
	R[u]=dfn;
}

void Build() {
	static queue <int> que;
	rep(i,0,25) if(trie[0][i]) que.push(trie[0][i]);
	while(!que.empty()) {
		int u=que.front(); que.pop();
		AddEdge(fail[u],u);
		rep(i,0,25) {
			int &v=trie[u][i];
			if(!v) v=trie[fail[u]][i];
			else fail[v]=trie[fail[u]][i],que.push(v);
		}
	}
	dfs(0);
}

struct BIT{
	int s[N];
	void Add(int p,int x){ while(p<=dfn) s[p]+=x,p+=p&-p; }
	int Que(int p){
		int res=0;
		while(p) res+=s[p],p-=p&-p;
		return res;
	}
	int Que(int l,int r){ return Que(r)-Que(l-1); }
} T;

char s[N];
int A[N],B[N],C;

int main(){
	n=rd();
	rep(i,1,n) {
		scanf("%s",s+1);
		int u=0;
		for(int j=1;s[j];++j) {
			int &v=trie[u][s[j]-\'a\'];
			if(!v) v=++cnt,fa[v]=u,dep[v]=dep[u]+1;
			u=v;
		}
		lst[End[i]=u]=u;
	}
	Build();
	int ans=0;
	rep(i,1,n) {
		C=0;
		for(int u=End[i],mi=1e9;u;u=fa[u]) {
			T.Add(L[u],1);
			int p=lst[u==End[i]?fail[u]:u];
			int l=dep[u]-dep[p]+1;
			if(!p || mi<=l) continue; // none or being included
			mi=l;
			if(!B[p]) A[++C]=p;
			B[p]++;
		}
		rep(j,1,C) {
			ans+=T.Que(L[A[j]],R[A[j]])==B[A[j]];
			B[A[j]]=0;
		}
		for(int u=End[i];u;u=fa[u]) T.Add(L[u],-1);
	}
	printf("%d\\n",ans);
}

以上是关于CF1483F的主要内容,如果未能解决你的问题,请参考以下文章

如何从后台弹出片段

cf 模拟

CF1435 游记

无法解析符号 c882c94be45fff9d16a1cf845fc16ec5

本人想学习破解技术但是看不懂反汇编代码!求助!!

微信小程序代码片段