【GDOI2017 day1 T3】微信 && SAM学习小记
来源:互联网 发布:算法之道实验指导书 编辑:程序博客网 时间:2024/05/16 05:12
SAM学习小记
【GDOI2017 day1 T3】微信
Description
Input
Output
Sample Input
3idont<<<<loveyoui<youlovemelovingyou2110111
Sample Output
43
Data Constraint
一道字符串题,比赛以前,只会KMP,ExKMP,SA,Manachar,Trie。。。一看这道题,放入Trie中,然后呢??
出题人说,用广义后缀自动机。啊啊啊?没学过啊
现在终于学了SAM,再看看这道题——水题!!!
后缀自动机(Suffix Automaton)
后缀自动机是一个用O(n)的复杂度,以遍历DAG的方式表示出一个或多个字符串的所有子串的东东
SAM中元素的一些成分
- S:原串
- x:DAG中的x节点其中
root→x 的最长路径为原串x的前缀 - nxt[x][c]:节点x所代表的串中拓展一个字符c到达的节点
- len[x]:
root→x 的最长路径长度 - pre[x]:x节点代表的前缀的最长后缀为pre[x]代表的前缀
- right(s):S中的所有子串s的末尾位置集合
- 节点x所表示的子串:
root→x 的所有路径代表的字符串
构造方式
注意根为1
实例:abacb:
①插入a
②这时las=2,插入b,2的fa链2-1,nxt[2][b]为空,nxt[2][b]=now,跳到1,重复执行操作,跳到0,结束,fa[now]=1
③插入a,las=3,las的fa链为3-1,nxt[3][a]为空,nxt[3][a]=now,跳到1,nxt[1][a]不为空,结束,nxt[1][a]=2,len[1]+1==len[2],fa[4]=2
④插入c
⑤插入b,nxt[4][b]=now,nxt[1][b]不为空,停止,nxt[1][b]=3,但len[1]+1!=len[3],新开节点7代表3(‘b’),1的fa链nxt[][b]=3的只有1,nxt[1][b]=7,fa[7]=fa[3],fa[now]=fa[3]=7
复杂度
O(n),不超过2n
int nw(int x){deep[++cnt]=x+1;/*deep就是len*/ return cnt;}void ins(int las,int c){ int now=nw(deep[las]); for(;las && !tr[las].nxt[c];las=tr[las].pre)tr[las].nxt[c]=now; if(!las)tr[now].pre=1;/*pre也就是fa*/ else{ int u=las,v=tr[u].nxt[c]; if(deep[u]+1==deep[v])tr[now].pre=v;else{ int _v=nw(deep[u]);tr[_v]=tr[v];tr[now].pre=tr[v].pre=_v; for(;u && tr[u].nxt[c]==v;u=tr[u].pre)tr[u].nxt[c]=_v; } }}
性质
- 状态x表示的长度范围
(lenprex,lenx] - 一个状态代表的不同字符串在原串中出现次数相等,且每次出现位置末位相同
right(x)⊆right(fax) - 后缀自动机的fa树是原串的反向前缀树
- 两个串的最长公共后缀位于所在fa树上的节点的最长公共祖先
求right:
大小:插入新字符时++count[now]
,最后按照DAG的深度count[fa[x]]+=count[x]
广义后缀自动机
其实就是trie上自动机,每次就在trie_parent[x]所在自动机上的节点后加上x就好了,构造方式完全一样
回到原题
Err?不就是道水题吗
将所有出现的串压到trie中,放入状态,再做广义后缀自动机就好了。
#include<cstring>#include<cstdio>#define M 1001001#define full 1048576#define max(a,b) (a>b?a:b)#define lowbit(x) (x&(-x))using namespace std;int f[full],cnt,tot,go[M][26],sta[M],n,q,root,p[M],fa[M],que[M],h,t,deep[M+M],v[M+M],b[M+M];struct SAM{int nxt[26],pre,sta;}tr[M+M];char s[M];bool dealt[full];int nw(int x){deep[++cnt]=x+1;return cnt;}void ins(int las,int c,int sta,int &to){ int now=nw(deep[las]);tr[now].sta|=sta;to=now; for(;las && !tr[las].nxt[c];las=tr[las].pre)tr[las].nxt[c]=now; if(!las)tr[now].pre=1;else{ int u=las,v=tr[u].nxt[c]; if(deep[u]+1==deep[v])tr[now].pre=v;else{ int _v=nw(deep[u]);tr[_v]=tr[v];tr[now].pre=tr[v].pre=_v; for(;u && tr[u].nxt[c]==v;u=tr[u].pre)tr[u].nxt[c]=_v; } }}int main(){ freopen("wechat.in","r",stdin); freopen("wechat.out","w",stdout); scanf("%d\n",&n);cnt=p[root=0]=1;tr[1].sta=(1<<n)-1; for(int i=1;i<=n;i++){ scanf("%s",s+1);sta[root]+=(1<<i-1); for(int t=1,len=strlen(s+1),now=0;t<=len;t++){ if(s[t]=='<')now=fa[now];else{ int x=s[t]-97,y;if(!go[now][x])go[now][x]=++tot; y=go[now][x];sta[y]|=1<<i-1;fa[y]=now;now=y; } } } for(h=0,que[t=1]=0;h!=t;) for(int x=que[++h],i=0;i<26;i++)if(go[x][i])ins(p[x],i,sta[que[++t]=go[x][i]],p[go[x][i]]); for(int i=1;i<=cnt;i++)b[deep[i]]++; for(int i=1;i<=cnt;i++)b[i]+=b[i-1]; for(int i=1;i<=cnt;i++)v[b[deep[i]]--]=i; for(int i=cnt;i;i--)tr[tr[v[i]].pre].sta|=tr[v[i]].sta,f[tr[v[i]].sta]=max(f[tr[v[i]].sta],deep[v[i]]); for(dealt[que[t=1]=(1<<n)-1]=1,h=0;h!=t;)for(int x=que[++h],T=x,i=lowbit(T);T;T-=i,i=lowbit(T)){ f[x-i]=max(f[x-i],f[x]);if(!dealt[x-i])dealt[que[++t]=x-i]=1; } scanf("%d\n",&q); for(int i=1;i<=q;i++){ int x=0; for(int j=1;j<=n;j++)if(getchar()-48)x+=1<<j-1; printf("%d\n",f[x]);scanf("\n"); } fclose(stdin);fclose(stdout); return 0;}
- 【GDOI2017 day1 T3】微信 && SAM学习小记
- 【jzoj5098】【GDOI2017 day1】【微信】【tire上建sam】
- 【GDOI2017 day1】微信
- 【GDOI2017 day1】微信
- 【GDOI2017 day1】微信
- 【JZOJ5098】【GDOI2017 day1】微信
- SAM学习小记
- 济南学习 Day1 T3 am
- 济南学习 Day1 T3 pm
- 【后缀自动机sam学习小记】
- 后缀自动机(SAM)学习小记
- GDKOI2016 Day1 T3 寻宝
- NOIP2013 DAY1 T3
- 集训Day1 T3 整除
- 【GDOI2017 day1】取石子游戏
- 【JZOJ5096】【GDOI2017 day1】房屋购置
- 【jzoj4982】【GDOI2017模拟2.23】【加密】【sam】
- NOIP2013 Day1 T3 货车运输
- java 统计文章中每个单词出现的次数
- 用JS写的N阶贝塞尔曲线升阶降阶以及拖拽
- 为什么Netflix没有运维岗位?
- 验证码类的使用之登录界面的实现
- AIDL的阐述
- 【GDOI2017 day1 T3】微信 && SAM学习小记
- Python中optparse(2.7版本后将被移除)转到argparse
- Spring 入门知识点笔记整理
- python 二维列表映射写入csv文件, 并上传OSS
- python基础笔记一
- HDOJ 2026 首字母变大写
- c++标准库
- 取出字符串中的整数和字符部分并分别输出
- Logistic回归分类中的梯度上升法