zoukankan      html  css  js  c++  java
  • BZOJ3413: 匹配

    题面:https://www.lydsy.com/JudgeOnline/problem.php?id=3413
    题解:
    首先考虑匹配次数的意义。可以看出匹配的过程就是拿(A)串的所有前缀
    (B)串一一匹配。考虑(A)串的每一位。设当前位一共被匹配了(f[i])次,
    那么答案即为(sum) (f[i])
    考虑(f[i])的组成。它包括了两个部分:匹配成功的次数和失配次数。
    其中,失配次数是可以单独计算的。
    我们可以给(A)串建立SAM,用(B)串在上面跑。
    如果跑到了0号节点,说明整个匹配过程是失败的,所以失配次数为(n)
    否则,失配次数就是跑到的那个节点的endpos最靠左的那个节点。
    至于如何记这个endpos,可以用线段树合并。具体实现就是先对所有SAM上
    的节点拓扑排序,然后从大到小合并上去即可。
    现在考虑匹配成功的次数。考虑(B)串在(A)串的SAM上跑的过程。
    每次跑到一个非根节点,这个节点的线段树上存有当前位置所有的endpos。
    设失配次数为(x),那么当前节点能计入贡献的只有endpos<=(x)的那些
    (注意这里的endpos代表的是一个前缀的一个子串),其他的那些因为已经匹配完了,
    所以不计入贡献。
    时间复杂度:(O(SlogS))(S)指的是(B)串总长)
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    template<class D>I read(D &res){
    	res=0;register D g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    const int INF=1e9+7;
    char c[101000];
    int n,m,leng,sum,root[202000],lc[4040000],rc[4040000],w[4040000];
    I modi(int &k,int l,int r,int x){
    	if(!k)k=++sum;w[k]++;
    	if(l==r)return;
    	re mid=(l+r)>>1;
    	if(x<=mid)modi(lc[k],l,mid,x);
    	else modi(rc[k],mid+1,r,x);
    }
    IN merge(int x,int y){
    	if(!x&&!y)return 0;
    	if(!x)return y;
    	if(!y)return x;
    	re now=++sum;
    	lc[now]=merge(lc[x],lc[y]);rc[now]=merge(rc[x],rc[y]);w[now]=w[x]+w[y];
    	return now;
    }
    IN ques_min(int k,int l,int r){
    	if(l==r)return l;
    	re mid=(l+r)>>1;
    	if(w[lc[k]])return ques_min(lc[k],l,mid);
    	else return ques_min(rc[k],mid+1,r);
    }
    inline ll ques_sum(int k,int l,int r,int lim){
    	if(!k||l>lim)return 0;
    	if(l==r||r<=lim)return w[k];
    	re mid=(l+r)>>1;
    	return ques_sum(lc[k],l,mid,lim)+ques_sum(rc[k],mid+1,r,lim);
    }
    namespace SAM{
    	ll ans;
    	int len[202000],link[202000],ch[202000][10],buc[202000],sa[202000],p,q,las,cur,tot,cle;
    	I add(int x){
    		len[cur=++tot]=len[las]+1,p=las,las=cur;
    		while(p&&!ch[p][x])ch[p][x]=cur,p=link[p];
    		if(!p){link[cur]=1;return;}
    		q=ch[p][x];
    		if(len[p]+1==len[q]){link[cur]=q;return;}
    		cle=++tot;len[cle]=len[p]+1,link[cle]=link[q];
    		memcpy(ch[cle],ch[q],sizeof(ch[q]));
    		while(p&&ch[p][x]==q)ch[p][x]=cle,p=link[p];
    		link[q]=link[cur]=cle;
    	}
    	I init(){
    		tot=las=1;
    		F(i,1,n)add(c[i]-'0'),modi(root[cur],1,n,i);
    		F(i,1,tot)buc[len[i]]++;
    		F(i,1,tot)buc[i]+=buc[i-1];
    		FOR(i,tot,1)sa[buc[len[i]]--]=i;
    		FOR(i,tot,1)if(sa[i]!=1)root[link[sa[i]]]=merge(root[link[sa[i]]],root[sa[i]]);
    	}
    	I ques(){
    		p=1;q=INF;
    		F(i,1,leng)p=ch[p][c[i]-'0'];
    		if(!p)ans=n;
    		else{
    			q=ques_min(root[p],1,n);
    			ans=q-leng;
    		}
    		p=1;
    		F(i,1,leng){
    			p=ch[p][c[i]-'0'];
    			if(!p)break;
    			ans+=ques_sum(root[p],1,n,q+i-leng);
    		}
    		printf("%lld
    ",ans);
    	}
    }
    int main(){
    	read(n);
    	scanf("%s",c+1);
    	SAM::init();
    	read(m);
    	while(m--){
    		scanf("%s",c+1);
    		leng=strlen(c+1);
    		SAM::ques();
    	}
    	return 0;
    }
    
  • 相关阅读:
    poj1837 Balance

    字符流
    字节流
    File类
    this和static
    异常
    接口
    抽象类
    多态
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/12170531.html
Copyright © 2011-2022 走看看