bzoj 4566: [Haoi2016]找相同字符【SAM上DP

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

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


您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值