BZOJ 3238: [Ahoi2013]差异【S(后)A(缀)M(树)上DP

80 篇文章 0 订阅
8 篇文章 0 订阅

啊我又在写SAM……

反正题里求的就是反串后缀树上的各关键点之间的路径长度和

于是……dp一下

像我比较菜……

在本题rank1的lxl大爷的指导下

……嗯每条边出现的次数就是子树里关键点个数siz[i]*(n-siz[i])……显然…………嗨呀我好菜啊QAQ这都看不出来QAQ看来是要退役了

啊……反正这样写常数还是……不大的吧?

#include<bits/stdc++.h>
//#define Flaze_naive
#define MAXN 500005
using namespace std;	char read_s[MAXN];
struct sam{
	int son[MAXN<<1][26],pre[MAXN<<1],dis[MAXN<<1];
	int Right[MAXN<<1];
	int p,np,q,nq,lst,cnt;
	int lth;
	
	void insert(int x){
		dis[np=++cnt]=dis[p=lst]+1;
		Right[np]=1,lst=np;
		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[q]==dis[p]+1)	return pre[np]=q,void();
		else{
			dis[nq=++cnt]=dis[p]+1;
			memcpy(son[nq],son[q],sizeof son[q]);
			pre[nq]=pre[q];
			pre[q]=pre[np]=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');
	}
	
	void build_(){
		lst=cnt=1;
		scanf("%s",read_s);
		lth=strlen(read_s);
		for(int i=lth-1;~i;--i)	insert(read_s[i]-'a');
	}
	
	int s[MAXN<<1],v[MAXN<<1];
	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 ans;
	void DP(){
		for(int i=cnt;i;--i){
			int now=s[i],fth=pre[now];
			Right[fth]+=Right[now];
			ans+=1ll*(dis[now]-dis[fth])*Right[now]*(lth-Right[now]);

//			int now=s[i],fth=pre[now],tmp=dis[now]-dis[fth];
//			sum[now]+=Right[now]*tmp;
//			ans+=sum[now]*Right[fth]+sum[fth]*Right[now];
//			Right[fth]+=Right[now],sum[fth]+=sum[now];
		}
	}
	
	
#ifdef Flaze_naive	
	char tmp[MAXN<<1];
	void dfs(int now,int stp){
		puts(tmp);
		for(int i=0;i<26;++i)
			if(son[now][i])
				tmp[stp]='a'+i,dfs(son[now][i],stp+1);
		tmp[stp]=' ';	
	}
#endif 
}SAM;

int main(){
	SAM.build_();
#ifdef Flaze_naive
	SAM.dfs(1,0);
#endif 
	SAM.sort();
	SAM.DP();
	printf("%lld",SAM.ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值