zoukankan      html  css  js  c++  java
  • 【LuoguP4081】[USACO17DEC]Standing Out from the Herd

    题目链接

    题意

    给定多个字符串,每个串中仅在该串中出现的本质不同的子串个数。

    Sol

    多串匹配想到用广义SAM。

    之后从串的匹配角度不是很好做。发现一个本质不同的串最多只会贡献到一个串的答案里。
    那么建完广义SAM后,如果我们能够知道那些点是只有一个串能够到达并且知道是哪个的话我们就可以直接把这个点代表的本质不同的串给贡献到对应串的答案中。

    这个很好办,我们在建广义SAM的时候不考虑串之间的匹配,建完后再拿着所有的串重新在广义SAM上跑一遍,当我们遍历到一个点(也就是该串的一个前缀)的时候,它的祖先链上的所有点就都是存在于这个串中的子串,对当前点打上一个标记。如果已有不同标记说明这个点以及它所有的祖先都不会对任何一个串的答案产生贡献,那么直接变成-1表示不对答案产生贡献。

    之后我们对 parent 树dfs求出每一个点的状态并且贡献答案就行了。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define Set(a,b) memset(a,b,sizeof(a))
    #define Copy(a,b) memcpy(a,b,sizeof(a))
    template<class T>inline void init(T&x){
    	x=0;char ch=getchar();bool t=0;
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    	if(t) x=-x;return;
    }typedef long long ll;
    const int N=1e5+10;
    const int MAXN=N<<1;
    ll ans[N];char S[N];
    int son[MAXN][26],pass[MAXN],len[MAXN],length[N],fa[MAXN];
    int lst=0,node=0;
    
    struct edge{
    	int to,next;
    }a[N<<1];
    int head[N<<1],cnt=0;
    inline void add(int x,int y){a[++cnt]=(edge){y,head[x]};head[x]=cnt;}
    int n;
    void Extend(int c){
    	if(son[lst][c]&&len[son[lst][c]]==len[lst]+1) lst=son[lst][c];
    	else {
    		int p=++node,u=lst;lst=p;len[p]=len[u]+1;
    		while(~u&&!son[u][c]) son[u][c]=p,u=fa[u];
    		if(~u) {
    			int v=son[u][c];
    			if(len[v]==len[u]+1) return void(fa[p]=v);
    			int q=++node;Copy(son[q],son[v]);
    			fa[q]=fa[v];len[q]=len[u]+1;fa[v]=fa[p]=q;
    			while(~u&&son[u][c]==v) son[u][c]=q,u=fa[u];
    		}
    	}return;
    }
    void Insert(char*s,int L){
    	lst=0;fa[0]=-1;
    	for(int i=1;i<=L;++i) Extend(s[i]-'a');
    	return;
    }
    void GO(char*s,int id,int L){
    	int u=0;
    	for(int i=1;i<=L;++i) {
    		int c=s[i]-'a';
    		u=son[u][c];
    		if(pass[u]>0) pass[u]=-1;
    		else if(!pass[u]) pass[u]=id;
    	}
    }
    void Dfs(int u){
    	for(int v,i=head[u];i;i=a[i].next) {
    		v=a[i].to;Dfs(v);
    		if(~pass[u]) {
    			if(!pass[u]) pass[u]=pass[v];
    			else if(pass[u]!=pass[v]) pass[u]=-1;
    		}
    	}
    	if(pass[u]>0) ans[pass[u]]+=len[u]-len[fa[u]];
    }
    int main()
    {
    	int L=0;init(n);
    	for(int i=1;i<=n;++i) {
    		scanf("%s",S+1+L);
    		length[i]=strlen(S+1+L);
    		Insert(S+L,length[i]);
    		L+=length[i];
    	}
    	for(int i=1;i<=node;++i) add(fa[i],i);L=0;
    	for(int i=1;i<=n;++i) GO(S+L,i,length[i]),L+=length[i];
    	Dfs(0);
    	for(int i=1;i<=n;++i) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    SQL Server中怎样可以从SELECT语句的结果集中删除重复行
    Comparison method violates its general contract!
    如何解决 不能以 DISTINCT 方式选择 text、ntext 或 image 数据类型
    TortoiseSVN—Repo-browser
    使用BigDecimal完成小数点后的精确位数的四舍五入
    CREATE TABLE 语句后的 ON [PRIMARY] 起什么作用
    sql server 获取每一个类别中值最大的一条数据
    C# 正则表达式
    Linq to XML 读取XML 备忘笔记
    安装双系统需要注意的几个问题
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/10899889.html
Copyright © 2011-2022 走看看