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));
}
}

浙公网安备 33010602011771号