zoukankan      html  css  js  c++  java
  • SAM 做题记录

    pigeon->gugugu();

    P3804 【模板】后缀自动机 (SAM)

    建出 SAM 后 在 parent tree 上 dp,对每个节点算它子树里面叶子节点个数,然后根据题意统计答案即可。

    Code
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000005*3;
    struct node{int len,link,to[30];};
    int n,hd[N],tot,sz[N];
    long long ans;
    char s[N];
    struct edge{int t,nxt;}es[N<<1];
    void add(int u,int v){es[++tot]=(edge){v,hd[u]};hd[u]=tot;}
    namespace SAM{
    	node state[N];
    	int rt=1,last=1,tot=1;
    	void extend(int ch){
    		int cur=++tot,p,q; 
    		sz[cur]=1;
    		state[cur].len=state[last].len+1;
    		for(p=last;p&&!state[p].to[ch];p=state[p].link)state[p].to[ch]=cur;
    		if(!p)state[cur].link=rt;
    		else{
    			q=state[p].to[ch];
    			if(state[p].len+1==state[q].len)state[cur].link=q;
    			else{
    				int clone=++tot;
    				state[clone]=state[q];
    				state[clone].len=state[p].len+1;
    				state[cur].link=state[q].link=clone;
    				for(;p&&state[p].to[ch]==q;p=state[p].link)state[p].to[ch]=clone;
    			}
    		}
    		last=cur;
    	}
    }
    void dfs(int u){
    	for(int i=hd[u];i;i=es[i].nxt)dfs(es[i].t),sz[u]+=sz[es[i].t];
    	if(sz[u]!=1)ans=max(ans,1LL*sz[u]*SAM::state[u].len);
    } 
    int main(){
    	scanf("%s",s);n=strlen(s);
    	for(int i=0;i<n;i++)SAM::extend(s[i]-'a');
    	for(int i=2;i<=SAM::tot;i++)add(SAM::state[i].link,i);
    	dfs(SAM::rt);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    P1368 【模板】最小表示法

    两倍长建 SAM,每次走最小的边,走 (n) 次即可。

    Code
    #include<bits/stdc++.h>
    using namespace std;
    const int N=300005*3;
    struct node{int len,link;map<int,int>to;};
    struct Suffix_Automation{
    	node state[N];
    	int rt=1,last=1,tot=1;
    	void extend(int ch){
    		int cur=++tot,p,q;
    		state[cur].len=state[last].len+1;
    		for(p=last;p&&!state[p].to[ch];p=state[p].link)state[p].to[ch]=cur;
    		if(!p)state[cur].link=rt;
    		else{
    			q=state[p].to[ch];
    			if(state[p].len+1==state[q].len)state[cur].link=q;
    			else{
    				int clone=++tot;
    				state[clone]=state[q];
    				state[clone].len=state[p].len+1;
    				state[cur].link=state[q].link=clone;
    				for(;p&&state[p].to[ch]==q;p=state[p].link)state[p].to[ch]=clone;
    			}
    		}
    		last=cur;
    	}
    }SAM;
    int n,a[N];
    map<int,int>::iterator it;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),SAM.extend(a[i]);
    	for(int i=1;i<=n;i++)SAM.extend(a[i]);
    	for(int i=1,nw=SAM.rt;i<=n;i++)it=SAM.state[nw].to.begin(),printf("%d ",it->first),nw=it->second;
    	return 0;
    }
    

    P3804 【模板】后缀自动机 (SAM)

    这题貌似和第一题很像,其实处理方法不一样。

    根据 (operatorname{link}) 的定义,状态 (v) 对应的字符串个数为 (operatorname{len}(i)-operatorname{len}(operatorname{link}(i))),那么每次加字符的时候更新就可以了。

    Code
    #include<bits/stdc++.h>
    using namespace std;
    const int N=300005*3;
    struct node{int len,link;map<int,int>to;};
    struct Suffix_Automation{
    	node state[N];
    	int rt=1,last=1,tot=1;
    	long long ans;
    	void extend(int ch){
    		int cur=++tot,p,q;
    		state[cur].len=state[last].len+1;
    		for(p=last;p&&!state[p].to[ch];p=state[p].link)state[p].to[ch]=cur;
    		if(!p)state[cur].link=rt;
    		else{
    			q=state[p].to[ch];
    			if(state[p].len+1==state[q].len)state[cur].link=q;
    			else{
    				int clone=++tot;
    				state[clone]=state[q];
    				state[clone].len=state[p].len+1;
    				ans-=state[q].len-state[state[q].link].len;
    				state[cur].link=state[q].link=clone;
    				ans+=state[q].len-state[state[q].link].len;
    				ans+=state[clone].len-state[state[clone].link].len;
    				for(;p&&state[p].to[ch]==q;p=state[p].link)state[p].to[ch]=clone;
    			}
    		}
    		ans+=state[cur].len-state[state[cur].link].len;
    		last=cur;
    	}
    }SAM;
    int n,a[N];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),SAM.extend(a[i]),printf("%lld
    ",SAM.ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Mybatis专栏文章整理成册《Mybatis进阶》!!!
    Mybatis的几种传参方式,你了解吗?
    HDU 1890
    POJ 2186
    HDU 2896
    POJ 1322
    POJ 1276
    POJ 1208
    POJ 1189
    POJ 1178
  • 原文地址:https://www.cnblogs.com/happydef/p/sam-todo.html
Copyright © 2011-2022 走看看