i号节点表示的不同串的个数是dis[pre[i]]-dis[i],而这个串出现的次数就是当前节点的right集合大小
于是就有奇怪的转移方程了
然后胡搞乱搞一切水到渠成【玄学吗x
#include<bits/stdc++.h>
#define MAXN 400057
using namespace std; char read_s[MAXN];
struct t1{
int son[MAXN][26],pre[MAXN],dis[MAXN];
int siz[MAXN];
int lst,cnt;
int lth;
int p,np,q,nq;
void insert(int x){
dis[np=++cnt]=dis[p=lst]+1;
lst=np;
siz[np]=1;
for(;p&&!son[p][x];p=pre[p]) son[p][x]=np;
if(!p) return pre[np]=1,void();
q=son[p][x];
if(dis[p]+1==dis[q]) pre[np]=q;
else{
dis[nq=++cnt]=dis[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
pre[nq]=pre[q];
pre[np]=pre[q]=nq;
for(;p&&son[p][x]==q;p=pre[p]) son[p][x]=nq;
}
}
void build(){
lst=cnt=1;
scanf("%s",read_s);
lth=strlen(read_s);
for(int i=0;i<lth;++i) insert(read_s[i]-'a');
}
int v[MAXN],s[MAXN];
void sort(){
for(int i=1;i<=cnt;++i) ++v[dis[i]];
for(int i=1;i<=lth;++i) v[i]+=v[i-1];
for(int i=1;i<=cnt;++i) s[v[dis[i]]--]=i;
}
long long f[MAXN];
void get_f(){
for(int i=cnt;i;--i)
siz[pre[s[i]]]+=siz[s[i]];
// for(int i=1;i<=cnt;++i) printf("pre=%d, siz=%d\n",pre[i],siz[i]);
for(int i=1;i<=cnt;++i){
int x=s[i];
f[x]=f[pre[x]]+1ll*(dis[x]-dis[pre[x]])*siz[x];
// printf("%d %lld\n",dis[x],f[x]);
}
}对于这种和parent有关的……要注意……是排序后的……排序后的……i是指针s[i]才是点的标号【跪地哭
long long ans;
void solve(){
scanf("%s",read_s);
int lth_b=strlen(read_s);
int tmp=0,now=1,x;
for(int i=0;i<lth_b;++i){
x=read_s[i]-'a';
if(son[now][x]) now=son[now][x],++tmp;
else{
for(;now&&!son[now][x];now=pre[now]);
if(!now) now=1,tmp=0;
else tmp=dis[now]+1,now=son[now][x];//……这个……很容易手快敲错……而且因为是SAM而不是树……所以dis[son[now][x]]不一定等于dis[now]+1
}
if(now!=1) ans+=f[pre[now]]+1ll*siz[now]*(tmp-dis[pre[now]]);
}
printf("%lld\n",ans);
}
#ifdef Flaze_Naive
char tmp[MAXN];
void dfs(int now,int stp){
for(int i=0;i<26;++i)
if(son[now][i]){
tmp[stp]='a'+i;
puts(tmp);
dfs(son[now][i],stp+1);
}
tmp[stp]=' ';
}
#endif
}SAM;
int main(){
SAM.build();
SAM.sort();
SAM.get_f();
SAM.solve();
#ifdef Flaze_Naive
SAM.dfs(1,0);
#endif
return 0;
}

该博客详细探讨了bzoj 4566题目的解决方案,主要涉及如何利用SAM(suffix automaton)和动态规划(DP)来找出字符串中相同字符的出现情况。博主介绍了关键思路,即计算每个SAM节点表示的不同串的数量,并利用节点的right集合大小来确定串的出现次数。通过建立奇特的转移方程,最终问题迎刃而解,展现了算法的巧妙应用。
626

被折叠的 条评论
为什么被折叠?



