首页 > 其他分享 >【学习笔记】SAM的应用

【学习笔记】SAM的应用

时间:2023-04-17 22:14:23浏览次数:47  
标签:SAM sam int lin 笔记 学习 len clone cur

command_block-SAM的应用
感谢大佬的指点

暴论:后缀数组什么辣鸡啊,再也不用后缀数组啦!加入SAM神教!


建出后缀自动机,可知一个串的出现次数即为endpos个数也是后缀链接树上的子节点个数。
同一endpos集合的子集中子串长度连续且长度区间为 \([maxlen(sam[cur].link)+1,maxlen(cur)]\) 。
两者乘起来即为答案,要开longlong

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar(); 
	}
	return f*j;
}
const int N=200010;
char s[N];
int n,cnt,du[N];
struct node{
	int lin,siz,len,to[26],sumn;
}sam[N];
inline int insert(int p,int sumn){
	int cur=++cnt;
	sam[cur].siz=1,sam[cur].len=sam[p].len+1,sam[cur].sumn=sumn;
	while(p&&!sam[p].to[sumn])sam[p].to[sumn]=cur,p=sam[p].lin;
	if(!p)return sam[cur].lin=1,cur;
	int q=sam[p].to[sumn];
	if(sam[q].len==sam[p].len+1)return sam[cur].lin=q,cur;
	int clone=++cnt;
	sam[clone]=sam[q],sam[clone].len=sam[p].len+1,sam[clone].siz=0;
	sam[q].lin=sam[cur].lin=clone;
	while(p&&sam[p].to[sumn]==q)sam[p].to[sumn]=clone,p=sam[p].lin;
	return cur;
}
void work(){
	long long ans=0;
	for(int i=1;i<=cnt;i++)sam[i]=sam[0],du[i]=0;
	scanf("%s",s+1),n=strlen(s+1);
	cnt=1;
	for(int last=1,i=1;i<=n;i++)last=insert(last,s[i]-'a');
	for(int i=1;i<=cnt;i++)du[sam[i].lin]++;
	deque<int>que;
	for(int i=1;i<=cnt;i++)if(!du[i])que.push_back(i);
	while(!que.empty()){
		int u=que.front();que.pop_front();
//		cout<<u<<":"<<sam[u].lin<<"-"<<sam[u].len<<" "<<sam[u].siz<<"-"<<(char)(sam[u].sumn+'a')<<"\n";
		ans+=1ll*(sam[u].len-sam[sam[u].lin].len)*sam[u].siz*sam[u].siz;
		sam[sam[u].lin].siz+=sam[u].siz,du[sam[u].lin]--;
		if(!du[sam[u].lin])que.push_back(sam[u].lin);
	}
	for(int i=1;i<=cnt;i++){
//		cout<<i<<":"<<sam[i].lin<<"-"<<sam[i].len<<" "<<sam[i].siz<<"-"<<(char)(sam[i].sumn+'a')<<"\n";
//		cout<<i<<" "<<sam[i].lin<<" "<<(char)(sam[i].sumn+'a')<<"\n";
		for(int j=0;j<=25;j++){
			if(!sam[i].to[j])continue;
//			cout<<i<<" "<<sam[i].to[j]<<" "<<(char)(sam[j].sumn+'a')<<"\n";
		}
		if(!du[i])que.push_back(i);
	}
	printf("%lld\n",ans);
	return ;
}
signed main(){
	int T=rd();
	while(T--)work();
	return 0;
}
/*
2
llalahaffl
jijhjjhhki
*/

动态构建后缀自动机,新增的后缀就是 sam[cur].len-sam[sam[cur].link].len

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}

const int N=100001;
struct node{
	unordered_map<int,int>to;
	int len,fro;
}sam[N*2];
int n,last,cnt;
long long ans;

void insert(int c){
	int p=last,now=++cnt;
	sam[now].len=sam[p].len+1;
	while(p&&(!sam[p].to[c]))sam[p].to[c]=now,p=sam[p].fro;
	last=now;
	if(!p)return sam[now].fro=1,void(0);
	if(sam[p].len+1==sam[sam[p].to[c]].len)return sam[now].fro=sam[p].to[c],void(0);
	int clone=++cnt,qnode=sam[p].to[c];
	sam[clone]=sam[qnode];
	sam[clone].len=sam[p].len+1;
	sam[qnode].fro=sam[now].fro=clone;
	while(p&&sam[p].to[c]==qnode)sam[p].to[c]=clone,p=sam[p].fro;
	return ;
}

signed main(){
	n=rd();
	last=cnt=1;
	for(int i=1;i<=n;i++){
		int x=rd();
		insert(x);
		ans+=sam[last].len-sam[sam[last].fro].len;
		printf("%lld\n",ans);
	}
//	for(int i=1;i<=cnt;i++)cout<<i<<":"<<sam[i].len<<" "<<sam[i].fro<<"\n";
	return 0;
}

很久之前写的代码,变量名可能不太一样。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=1000010;
char s[N];
int n,cnt=1;
int siz[N],lin[N],len[N],sum[N],to[N][26],num[N];
int t[N],A[N];
inline int insert(int p,int sumn){
	int cur=++cnt;
	siz[cur]=1,len[cur]=len[p]+1,num[cur]=sumn;
	while(p&&!to[p][sumn])to[p][sumn]=cur,p=lin[p];
	if(!p)return lin[cur]=1,cur;
	int q=to[p][sumn];
	if(len[p]+1==len[q])return lin[cur]=q,cur;
	int clone=++cnt;
	len[clone]=len[p]+1,lin[clone]=lin[q],num[clone]=num[q];
	memcpy(to[clone],to[q],sizeof(to[q]));
	lin[q]=lin[cur]=clone;
	while(p&&to[p][sumn]==q)to[p][sumn]=clone,p=lin[p];
	return cur;
}
void dfs(int u,int Sum){
	Sum-=siz[u];
	if(Sum<0)return ;
	if(u!=1)putchar(num[u]+'a');
	if(Sum<=0)return ;
	for(int i=0;i<26;i++){
		if(!to[u][i])continue;
		if(Sum>sum[to[u][i]])Sum-=sum[to[u][i]];
		else{
//			cout<<u<<":"<<(char)(i+'a')<<"-"<<to[u][i]<<" "<<sum[to[u][i]]<<"-"<<Sum<<"\n";
			dfs(to[u][i],Sum);
			break;
		}
	}
	return ;
}
signed main(){
	scanf("%s",s+1),n=strlen(s+1);
	int T=rd(),K=rd();
	for(int i=1,last=1;i<=n;i++)last=insert(last,s[i]-'a');
	for(int i=1;i<=cnt;i++)t[len[i]]++;
	for(int i=1;i<=n;i++)t[i]+=t[i-1];
	for(int i=cnt;i>=1;i--)A[t[len[i]]--]=i;
	for(int i=cnt;i>=1;i--)siz[lin[A[i]]]+=siz[A[i]];
	for(int i=1;i<=cnt;i++)sum[i]=(!T)?(siz[i]=1):siz[i];
	sum[1]=siz[1]=0;
	for(int i=cnt;i>=1;i--){
		int u=A[i];
		for(int j=0;j<26;j++){
			if(!to[u][j])continue;
			sum[u]+=sum[to[u][j]];
		}
	}
	if(sum[1]<K)return printf("-1\n"),0;
	dfs(1,K);
	return 0;
}
/*
aaaaa
1 15
*/

  • SP1811
    SAM在类似AC机方面的作用,是把所有子串插入AC机。
    但是要注意当前点的长度并不是匹配上的串的长度,但跳link之后的长度一定是匹配上的串的长度。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
struct node{
	int len,lin,to[26];
}sam[N];
int n,cnt=1,ans;
char s[N];
inline int insert(int p,int sumn){
	int cur=++cnt;
	sam[cur].len=sam[p].len+1;
	while(p&&!sam[p].to[sumn])sam[p].to[sumn]=cur,p=sam[p].lin;
	if(!p)return sam[cur].lin=1,cur;
	int q=sam[p].to[sumn];
	if(sam[p].len+1==sam[q].len)return sam[cur].lin=q,cur;
	int clone=++cnt;
	sam[clone]=sam[q],sam[clone].len=sam[p].len+1;
	sam[q].lin=sam[cur].lin=clone;
	while(p&&sam[p].to[sumn]==q)sam[p].to[sumn]=clone,p=sam[p].lin;
	return cur;
}
signed main(){
	scanf("%s",s+1),n=strlen(s+1);
	for(int i=1,last=1;i<=n;i++)last=insert(last,s[i]-'a');
	scanf("%s",s+1),n=strlen(s+1);
	for(int i=1,cur=1,len=0;i<=n;i++){
		while(cur&&!sam[cur].to[s[i]-'a'])cur=sam[cur].lin,len=sam[cur].len;
		if(cur)cur=sam[cur].to[s[i]-'a'],len++,ans=max(ans,len);
		else cur=1,len=0;
	}
	printf("%d\n",ans);
	return 0;
}

标签:SAM,sam,int,lin,笔记,学习,len,clone,cur
From: https://www.cnblogs.com/flywatre/p/17327696.html

相关文章

  • 小白零基础python学习记录1
    Python程序格式框架缩进缩进用于表达程序的格式框架,有单层或多层缩进。严格明确:缩进是语法的一部分,缩进不正确程序运行会出错所属关系:是表达代码间包含和层次关系的唯一手段长度一致:程序内一致即可,一般用4个空格或1个Tab注释单行注释:以#开头,后跟注释句子多......
  • python学习---字符串格式化
    字符串格式化 数字和字符串的拼接   快速方法f,{} ......
  • python魔术方法学习总结代码
    classmyclass:name=Noneage=Nonedef__init__(self,name,age):"""魔术方法!!!类的构造方法:paramname::paramage:"""self.name=nameself.age=age......
  • 梦断代码读书笔记1
    这个月我开始了对《梦断代码》这本书的阅读。《梦断代码》一书记录的是作者罗森伯格对OSAF主持的Chandler项目进行田野调查,通过Chandler开发过程来揭示软件开发过程中一些根本性的大问题。对本书才刚刚阅读了三分之一,就已经忍不住对作者描述的开发过程所感叹,虽然刚进入软件领域不......
  • gateway网关入门级学习
    gateway目录旁边可以查询具体的目录结构和跳转一.网关介绍这样的架构,会存在着诸多的问题:​ 1.每个业务都会需要鉴权、限流、权限校验、跨域等逻辑,如果每个业务都各自为战,自己造轮子实现一遍,会很蛋疼,完全可以抽出来,放到一个统一的地方去做。​ 2.如果业务量比较简单的话,这种......
  • 学习技术点的历史时间线
    2023年:2023年4月17日-2023年4月25日:(首页公告栏有通知)在博客将发布Docker技术点的相关博文:(1)4月17日:标题:Docker基础知识点:https://www.cnblogs.com/liuyuchengcj/p/17326838.html......
  • :)深度学习模型如何统计params量-|
    :)深度学习模型如何统计params量-|1大概统计已知模型大小,如312M计算为312000000Bytes,浮点数据一个参数占4个字节,importtransformersimporttorchimportosfromtransformersimportGPT2TokenizerFast,GPT2LMHeadModel,GPT2ConfigfromtransformersimportBertT......
  • 《用户故事与敏捷方法》读书笔记4
    用户故事和Scrum团队需要逐步地完善整个系统,不断地给软件添加更多的细节,软件的功能也由此越来越完备。Scrum是敏捷方法中一种迭代递增的软件过程,实施scrum过程的项目往往采用30天为周期的迭代,称为Sprint,团队确认这个Sprint需要完成的工作,将所有任务放到成为产品Backlog的列表中......
  • Git基础内容笔记
    Git笔记更多gitlog命令可查看:http://git-scm.com/docs/git-log目录Git笔记Git工作流程一、Git的下载和安装1.1Ubuntu系统下载1.2Windows系统下载1.3设置用户名和邮箱二、基本使用2.1创建仓库gitinitgitclone2.2添加文件2.3提交文件至本地仓库gitadd命令gitcommi......
  • 4.17每日学习总结
    昨天对页面功能进行一些完善,实现添加了部分功能今天上课时打算与队友进行一些沟通,对一些任务更加明确些,遇到的困难是在查找有效的问题解决方法比较耗费时间。 ......