BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

时间:2023-03-10 05:58:57
BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

http://www.lydsy.com/JudgeOnline/problem.php?id=3238

就算是全局变量,也不要忘记,初始化(吐血)。

长得一副lca样,没想到是个树形dp(小丫头还有两幅面孔呢)。

看代码实现吧,不大容易口头解释,把加的和减的分开算就可以了,减去的通过倒着建sam(相当于建一棵后缀树),然后算每个len取的次数实现,注意树归中一些避免重复操作。

 /**************************************************************
Problem: 3238
User: 137shoebills
Language: C++
Result: Accepted
Time:3816 ms
Memory:130688 kb
****************************************************************/ #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int maxn=;
char ch1[maxn]={};
int siz;
struct nod{
int sig[];
int f,len;
}t[maxn*];int tot=,la=;
void add(int z){
int x=++tot;int i=la;
t[x].len=t[la].len+;
for(;i&&!t[i].sig[z];i=t[i].f)
t[i].sig[z]=x;
if(!i)t[x].f=;
else{
int p=t[i].sig[z];
if(t[p].len==t[i].len+)t[x].f=p;
else{
int y=++tot;
t[y]=t[p];t[y].len=t[i].len+;
t[x].f=t[p].f=y;
for(;i&&t[i].sig[z]==p;i=t[i].f)
t[i].sig[z]=y;
}
}
la=x;
}
struct node{
int y,next;
}e[maxn*];int cnt=;
int head[maxn*]={};
long long dp[maxn*]={},sum=;
void init(int x,int y){e[++cnt].y=y;e[cnt].next=head[x];head[x]=cnt;}
void dfs(int x){
int y;
long long num=dp[x]*dp[x];
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
dfs(y);dp[x]+=dp[y];
num+=dp[y]*dp[y];
}
sum+=(dp[x]*dp[x]-num)*t[x].len;
}
long long solve(){
int j=;
for(int i=siz;i>=;i--){
j=t[j].sig[ch1[i]-'a'];
dp[j]++;
}
for(int i=;i<=tot;i++)
init(t[i].f,i);
dfs();
return sum;
}
int main(){
memset(t,,sizeof(t));
scanf("%s",ch1+);siz=strlen(ch1+);
for(int i=siz;i>=;i--)add((int)(ch1[i]-'a'));
long long ans=;
for(int i=;i<=siz;i++)ans+=(long long)i*(siz-);
printf("%lld\n",ans-solve());
return ;
}