#2033. 「SDOI2016」生成魔咒(广义SAM)

#2033. 「SDOI2016」生成魔咒(广义SAM)

题意:求字符串所有前缀的本质不同的字符串个数 。

此题唯一的亮点是:字符集 Σ |\Sigma| 较大,因为是每个字符是数字,所以考虑用 m a p map 存,然后每次插入字符后,更新并输出答案即可, a n s + = l e n [ n p ] l e n [ f a [ n p ] ] ans+=len[np]-len[fa[np]]

另外此题还可以跑拓扑或者 d f s dfs 状态转移。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=8e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false),cin.tie(0)
int n,q,tot,num; 
char s[N];
map<int,int>mp;
struct SAM{
	int last,cnt;map<int,int>ch[N];
	int fa[N],len[N];
	ll ans=0;
	void insert(int c){
		int p=last,np=++cnt;last=np;len[np]=len[p]+1;
		for(;p&&!ch[p].count(c);p=fa[p]) ch[p][c]=np;
		if(!p) fa[np]=1;
		else {
			int q=ch[p][c];
			if(len[q]==len[p]+1) fa[np]=q;
			else  {
				int nq=++cnt;len[nq]=len[p]+1;
				ch[nq]=ch[q];
				fa[nq]=fa[q],fa[q]=fa[np]=nq;
				for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
			}
		}
		ans+=len[np]-len[fa[np]];//重要. 
	}
	void build(){
		last=cnt=1;
		int n,x;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&x);
			if(!mp[x]) mp[x]=++num;
			insert(mp[x]);
			printf("%lld\n",ans);
		}
	}
}sam;
int main(){
	sam.build();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/107506636