zoukankan      html  css  js  c++  java
  • [BZOJ3473]字符串

    话说广义后缀自动机原来是这么建的...

    这道题算是一道广义后缀自动机的模板题,和后缀数组的感觉差不多啊.

    这题的一个难点在于如何求出每个节点的子串在多少个字符串中出现过.

    原本的想法是差分,后来发现我SB了,差分只能解决数量上的问题,不能解决这种存在性的问题(?).

    本来想搞一个Set玩启发式合并,但是貌似可以用一种类似于暴力的方法(?),对于当前跑的这个字符串,在后缀自动机上跑到了now,

    那么就把now的所有祖先节点全部打上标记,如果遇到了打上标记的点,直接break就行了,复杂度貌似N乘根号N.而且这是最坏情况.

    最后统计答案即可.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<iomanip>
    using namespace std;
    #define ll long long
    #define db double 
    #define up(i,j,n) for(int i=j;i<=n;i++)
    #define pii pair<int,int>
    #define uint unsigned int
    #define FILE "dealing"
    #define eps 1e-4
    int read(){
    	int x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return x*f;
    }
    template<class T> bool cmax(T& a,T b){return a<b?a=b,true:false;}
    template<class T> bool cmin(T& a,T b){return a>b?a=b,true:false;}
    const int maxn=100060,limit=50100,inf=1000000000,r=3,mod=1000000007;
    int n,k;
    string s[maxn];
    namespace SAM{
    	const int maxn=201000;
    	int np,nq,q,p,now,cnt=1,sa[maxn],c[maxn][26],val[maxn],count[maxn],pre[maxn],len[maxn],v[maxn],f[maxn],ccnt[maxn];
    	vector<int> E[maxn];
    	int extend(int x){
    		p=now;np=now=++cnt;len[np]=len[p]+1;
    		while(p&&!c[p][x])c[p][x]=np,p=pre[p];
    		if(!p)pre[np]=1;
    		else {
    			q=c[p][x];
    			if(len[q]==len[p]+1)pre[np]=q;
    			else{
    				len[nq=++cnt]=len[p]+1;
    				memcpy(c[nq],c[q],sizeof(c[q]));
    				pre[nq]=pre[q];
    				pre[q]=pre[np]=nq;
    				while(p&&c[p][x]==q)c[p][x]=nq,p=pre[p];
    			}
    		}
    		return np;
    	}
    	void build(int id){
    		now=1;
    		int n=s[id].size();
    		up(i,0,n-1)val[extend(s[id][i]-'a')]=id;
    	}
    	void prepare(){
    		up(i,1,cnt)count[len[i]]++;
    		up(i,1,cnt)count[i]+=count[i-1];
    		for(int i=cnt;i>=1;i--)sa[count[len[i]]--]=i;
    		up(i,1,cnt){
    			int x=sa[i];
    			f[x]=f[pre[x]]+(ccnt[x]>=k)*(len[x]-len[pre[x]]);
    		}
    		
    	}
    	int Len=0;
    	int walk(int x){
    		while(pre[now]&&!c[now][x])now=pre[now],Len=len[now];
    		if(!c[now][x])return 0;
    		now=c[now][x];Len++;
    		return Len;
    	}
    	int vis[maxn];
    	void GO(int id){
    		int n=s[id].size();
    		now=1;Len=0;vis[now]=id;
    		up(i,0,n-1){
    			int x=s[id][i]-'a';
    			walk(x);
    			int tmp=now;
    			for(;vis[tmp]!=id;tmp=pre[tmp]){
    				vis[tmp]=id;
    				ccnt[tmp]++;
    			}
    		}
    	}
    };
    int main(){
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    	n=read(),k=read();
    	up(i,1,n){
    		cin>>s[i];
    		SAM::build(i);
    	}
    	up(i,1,n)SAM::GO(i);
    	SAM::prepare();
    	ll ans=0;
    	up(i,1,n){
    		ans=0;
    		int m=s[i].size();
    		SAM::now=1;SAM::Len=0;
    		up(j,0,m-1){
    			SAM::walk(s[i][j]-'a');
    			ans+=SAM::f[SAM::now];
    		}
    		printf("%lld ",ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    input宽度自适应
    七牛云上传 图片
    删除文件夹所有内容
    无法获取 div123 的内部内容,因为该内容不是文本。
    关于"无法删除数据库 'xxx',因为该数据库当前正在使用" 解决办法
    Asp.Net 获取FileUpload控件的文件路径、文件名、扩展名
    asp.net复制整个文件夹
    多行文本框内容转换空格换行
    花(唯一分解定理+排列组合+快速幂)
    Xn数列(矩阵乘法+快速幂+慢速乘法)
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6559271.html
Copyright © 2011-2022 走看看