CF802I Fake News (hard) 题解

Description

求一个字符串的每一种子串出现次数平方。

Solution

拍到 SAM 里,在 parent tree 上统计每一个状态节点所代表的一类子串出现次数,直接平方并乘上这个节点代表的子串数量。

时间复杂度 \(O(\sum \left| s \right|)\)

代码:

#include<bits/stdc++.h>
#define N 100005
#define F(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
struct state{int to[26],len,link,cnt;}st[N<<1];
int T,sz,lst;
long long ans;
string s;
inline void insert(int c){
	int cur=++sz,p=lst;
	st[cur].cnt=1,st[cur].len=st[lst].len+1,lst=cur,st[cur].cnt=1;
	while(p!=-1&&!st[p].to[c])st[p].to[c]=cur,p=st[p].link;
	if(p==-1)return;
	int q=st[p].to[c];
	if(st[p].len+1==st[q].len)return st[cur].link=q,void();
	int clone=++sz;
	st[clone]=st[q],st[clone].len=st[p].len+1,st[clone].cnt=0;
	while(p!=-1&&st[p].to[c]==q)st[p].to[c]=clone,p=st[p].link;
	st[q].link=st[cur].link=clone;
}
vector<int>t[N<<1];
inline void dfs(int u){
	for(int v:t[u])dfs(v),st[u].cnt+=st[v].cnt;
	if(u)ans+=1ll*(st[u].len-st[st[u].link].len)*st[u].cnt*st[u].cnt;
}
int main(){
	cin>>T;
	while(T--){
		sz=lst=ans=0;
		st[0].link=-1;
		cin>>s;
		F(i,0,(int)s.length()-1)insert(s[i]-'a');
		F(i,1,sz)t[st[i].link].push_back(i);
		dfs(0),cout<<ans<<'\n';
		F(i,0,sz)t[i].clear();
		memset(st,0,(sizeof st[0])*(sz+1));
	}
}
posted @ 2025-06-17 11:59  linjingxiang  阅读(11)  评论(0)    收藏  举报