Bzoj4516:[Sdoi2016]生成魔咒:哈希表+后缀自动机

本文介绍了解决SOI2016生成魔咒问题的方法,采用SAM(Suffix Automation)结合Hashset实现。通过具体代码展示了如何在SAM中嵌套Hashset来处理字符串匹配及更新过程中的状态转移。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:4516:[Sdoi2016]生成魔咒

裸sam,但是显然要用hash,于是我在sam里套了个hashset,交的时候总感觉内存虚虚的,还怕RE……

不过还好直接AC辣~\(≧▽≦)/~

#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=150010;
const int maxb=50;
const int mod=41;
int n; LL ans=0;

inline int read(){
	int ret=0; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar())
	ret=ret*10+ch-'0'; return ret;
}

struct hashset{
	int next[maxb],val[maxb],As[maxb];
	int h[mod],tot;
	void init(){
		tot=0; memset(h,0,sizeof(h));
	}
	void push(int x,int id){
		int now=x%mod; if (now<0) now+=mod;
		for (int i=h[now];i;i=next[i])
		    if (val[i]==x) return;
		++tot; next[tot]=h[now]; h[now]=tot;
		val[tot]=x; As[tot]=id; return;
	}
	int find(int x){
		int now=x%mod; if (now<0) now+=mod;
		for (int i=h[now];i;i=next[i])
		    if (val[i]==x) return As[i];
		return -1;
	}
	void repush(int x,int id){
		int now=x%mod; if (now<0) now+=mod;
		for (int i=h[now];i;i=next[i])
		    if (val[i]==x){As[i]=id;return;}
	}
}son[maxn];

struct suffix_automation{
	int fa[maxn];
	int l[maxn],last,tot,root;
	void init(){
		tot=0; last=root=++tot;
	}
	int add(int x){
		int p=last,np=++tot; last=np; l[np]=l[p]+1; 
		while (p&&son[p].find(x)==-1) son[p].push(x,np),p=fa[p];
		if (!p) fa[np]=root;
		else{
			int q=son[p].find(x);
			if (l[q]==l[p]+1) fa[np]=q;
			else{
				int nq=++tot; fa[nq]=fa[q]; l[nq]=l[p]+1;
				for (int i=1;i<=son[q].tot;++i){
					son[nq].next[i]=son[q].next[i];
					son[nq].As[i]=son[q].As[i];
					son[nq].val[i]=son[q].val[i];
				}
				for (int i=0;i<mod;++i) son[nq].h[i]=son[q].h[i];
				son[nq].tot=son[q].tot; fa[q]=fa[np]=nq;
				while (son[p].find(x)==q) son[p].repush(x,nq),p=fa[p];
			}
		}return l[np]-l[fa[np]];
	}
}sam;

int main(){
	sam.init();
	scanf("%d",&n); int x;
	for (int i=1;i<=n;++i)
	    printf("%lld\n",ans+=sam.add(x=read()));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值