CF452E Three strings【广义SAM】

传送门

也是广义 SAM 的板子题,建好广义 SAM,统计 \(epA,epB,epC\),然后对于区间 \(ans[len[fa[x]]+1],...,ans[len[x]]\) 加上 \(epA\times epB\times epC\) 就行了,当然这个用差分实现简单快捷。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=3e5+10;
const int mod=1e9+7;
int A[N*2],B[N*2],C[N*2];
LL ans[N];
int slen,n=mod;
char s[N];
struct SuffixAutoMachine{
	int tot=1,len[N*2],fa[N*2],ch[N*2][26],*epos,a[N*2],c[N];
	int newnode(int x){fa[++tot]=fa[x];len[tot]=len[x];memcpy(ch[tot],ch[x],sizeof(ch[tot]));return tot;}
	int extend(int p,int c){
		int q=ch[p][c],nq=newnode(q);
		len[nq]=len[p]+1;fa[q]=nq;
		for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
		return nq;
	}
	int append(int p,int c){
		if(ch[p][c]) if(len[ch[p][c]]==len[p]+1) return ch[p][c];else return extend(p,c);
		int np=newnode(0);len[np]=len[p]+1;
		for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
		if(!p) fa[np]=1;
		else if(len[ch[p][c]]==len[p]+1) fa[np]=ch[p][c];
		else fa[np]=extend(p,c);
		return np;
	}
	void insert(int *_epos){
		int last=1;epos=_epos;
		for(int i=1;i<=slen;i++) last=append(last,s[i]-‘a‘),epos[last]=1;
	}
	void solve(){
		for(int i=1;i<=tot;i++) c[len[i]]++;
		for(int i=1;i<N;i++) c[i]+=c[i-1];
		for(int i=tot;i>=1;i--) a[c[len[i]]--]=i;
		for(int i=tot;i>1;i--){
			A[fa[a[i]]]+=A[a[i]];
			B[fa[a[i]]]+=B[a[i]];
			C[fa[a[i]]]+=C[a[i]];
		}
		for(int i=2;i<=tot;i++){
			LL x=1ll*A[i]*B[i]%mod*C[i]%mod;
			ans[len[fa[i]]+1]+=x;
			ans[len[i]+1]-=x;
		}
		for(int i=1;i<=n;i++) ans[i]=((ans[i-1]+ans[i])%mod+mod)%mod;
		for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
	}
}sam;

int main(){
	scanf("%s",s+1),slen=strlen(s+1);
	sam.insert(A);n=min(slen,n);
	scanf("%s",s+1),slen=strlen(s+1);
	sam.insert(B);n=min(slen,n);
	scanf("%s",s+1),slen=strlen(s+1);
	sam.insert(C);n=min(slen,n);
	sam.solve();
	return 0;
}

到这里,我后缀自动机的刷题基本结束了,虽然题单上还有很多难题没有刷,但那些都是结合了其他算法的题,对于 SAM 和广义 SAM 的原理和性质有了一些基本的了解就是这几天的主要任务了,也熟练的掌握了写法,效果还不错。之后也会慢慢把那些难题补完的。

下一步计划学习线段树合并。

原文地址:https://www.cnblogs.com/BakaCirno/p/12670860.html

时间: 2024-07-31 19:09:03

CF452E Three strings【广义SAM】的相关文章

【HDU 4436】 str2int (广义SAM)

str2int Problem Description In this problem, you are given several strings that contain only digits from '0' to '9', inclusive.An example is shown below.101123The set S of strings is consists of the N strings given in the input file, and all the poss

【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 974  Solved: 573 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建

bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】

把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i-1],f[j]+i-j(i-a[i]<=j<=i-L)},根据性质,i-a[i]是单调的(或者直接看a[i]的预处理过程也能看出来),所以这个dp可以用单调队列优化转移,最后判断是否f[n]>=L*0.9 #include<iostream> #include<cstdio

luogu3346 诸神眷顾的幻想乡 (广义SAM)

首先,让每一个叶节点做一次树根的话,每个路径一定至少有一次会变成直上直下的 于是对于每个叶节点作为根产生的20个trie树,把它们建到同一个广义SAM里 建法是对每个trie dfs去建,last就是父亲的那个节点:每次做一个新trie时,last给成root 然后答案就是每个节点表示的长度和 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4

喵星球上的点名——记一个用广义SAM根号维护多串的技巧

喵星球的上的点名 给定一个字符串集合S,每次给定T询问S中有多少个字符串中包含T,最后询问S中的每一个字符串包含了多少次给定的T. 思路 考虑将这S个字符串建立广义SAM,那么我们每次将T放到广义SAM中去匹配,最后匹配到的节点的parent子树中来自不同串的结束位置数就是第一问的答案. 同样我们每次匹配完之后在节点处打上标记,第二问S中每一个字符串的答案就是每一个结束位置能够一直往上跳链跳到的不同的节点的标记之和. 考虑如何实现上述过程,在广义SAM中,假设一个节点在SAM中的有效节点数量为\

bzoj5084 hashit 广义SAM+树链的并

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5084 题解 考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数. 对于一个常规的 SAM,这个东西应该是 \(\sum\limits_{i\in V} len_i - len_{fa_i}\). 很容易发现,我们如果把这个字符串每一个时刻的前一个字符和后一个字符给连接起来,这是一个树的关系. 考虑对这个树建立一棵广义 SAM. 但是上面的结论在广义 SAM 中不适用.不适用的

关于SAM和广义SAM

关于SAM和广义SAM 不是教程 某些思考先记下来 SAM 终于学会了这个东西诶...... 一部分重要性质 确定一个重要事情,S构造出的SAM的一个重要性质是当且仅当对于S的任意一个后缀,可以从1号节点走到终止状态.专业的名词叫做有限状态自动机. trans[st][c]表示的是对于状态st,如果将st中任意串s加一个c,那么会到达的新状态new,显然new是唯一的.假如不唯一那么s一定不属于同一个st. fa[st]表示的是对于状态st,如果慢慢缩小st中后缀长度,会到达的第一个状态.规定一

[HAOI2016]找相同字符(广义SAM)

[HAOI2016]找相同字符(广义SAM) 题面 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. 分析 此题有一个比较繁琐的后缀数组做法,但是用广义SAM可以秒杀. 把两个串建成广义SAM,对于每个后缀,记录\(endpos\)集合中落在第一个串中和第二个串中的位置个数,记为\(cnt_{x,0},cnt_{x,1}\). 对于自动机上的每个节点\(x\),出现位置方案数的贡献是\(cnt_{x,0} \cdot c

Codeforces 452E Three strings 字符串 SAM

原文链接https://www.cnblogs.com/zhouzhendong/p/CF542E.html 题目传送门 - CF452E 题意 给定三个字符串 $s1,s2,s3$ ,对于所有 $L\in{1,2,\cdots,min(|s1|,|s2|,|s3|)}$ ,输出 $f(L)$ . 其中 $f(L)$ 表示满足 $s_k[i_k,\cdots,i_k+L-1]$ 全部相同的 $i_1,i_2,i_3$ 的个数. 答案对 $10^9+7$ 取模. $|s1|+|s2|+|s3|\l