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

    BZOJ3413: 匹配


    题目描述

    传送门

    题目分析

    我们设询问串为(t)从头开始的第一个字符串为(s[1]),设在位置(x)匹配成功,则题目要求的就是(sum_{i=1}^xlcp(s[i],t))

    可以考虑先对(s)建立后缀自动机,然后考虑每一个(endpos)类会对答案造成多少贡献。

    明显可以发现匹配位置之后的都对答案没有贡献,所以可以使用线段树合并维护(right)集合,查询的时候直接查匹配位置前面的部分即可。

    是代码呢

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2e5+7;
    #define mid ((l+r)>>1)
    int n,m,T[MAXN],st[MAXN<<5],L[MAXN<<5],R[MAXN<<5],sz;
    char s[MAXN];
    inline void modify(int &u,int l,int r,int k)
    {
    	if(!u) u=++sz;
    	st[u]++;
    	if(l==r) return;
    	if(mid>=k) modify(L[u],l,mid,k);
    	else modify(R[u],mid+1,r,k);
    }
    inline int query(int u,int l,int r,int dl,int dr)
    {
    	if(dl<=l&&r<=dr) return st[u];
    	int ans=0;
    	if(dl<=mid) ans+=query(L[u],l,mid,dl,dr);
    	if(dr>mid) ans+=query(R[u],mid+1,r,dl,dr);
    	return ans;
    }
    inline int merge(int u,int v)
    {
    	if(!u||!v) return u+v;
    	int rt=++sz;
    	st[rt]=st[u]+st[v];
    	L[rt]=merge(L[u],L[v]);R[rt]=merge(R[u],R[v]);
    	return rt;
    }
    struct SAM{
    	int trans[MAXN][27],maxlen[MAXN],fa[MAXN],od[MAXN],pos[MAXN],wt[MAXN];
    	int cnt,last,p,np,q,nq;
    	SAM(){last=++cnt;}
    	inline void insert(int x,int id){
    		p=last;last=np=++cnt;maxlen[np]=maxlen[p]+1;pos[np]=id;
    		modify(T[np],1,n,id);
    		while(!trans[p][x]&&p) trans[p][x]=np,p=fa[p];
    		if(!p) fa[np]=1;
    		else {
    			q=trans[p][x];
    			if(maxlen[q]==maxlen[p]+1) fa[np]=q;
    			else {
    				nq=++cnt;maxlen[nq]=maxlen[p]+1;
    				pos[nq]=pos[q];
    				memcpy(trans[nq],trans[q],sizeof(trans[q]));
    				fa[nq]=fa[q];fa[q]=fa[np]=nq;
    				while(trans[p][x]==q) trans[p][x]=nq,p=fa[p];
    			}
    		}
    	}
    	inline void get_right(){
    		for(int i=1;i<=cnt;i++) wt[maxlen[i]]++;
    		for(int i=1;i<=n;i++) wt[i]+=wt[i-1];
    		for(int i=cnt;i;i--) od[wt[maxlen[i]]--]=i;
    		for(int i=cnt;i>1;i--) T[fa[od[i]]]=merge(T[fa[od[i]]],T[od[i]]),pos[fa[od[i]]]=min(pos[fa[od[i]]],pos[od[i]]);
    	}
    	inline int check(){
    		int now=1;
    		for(int i=1,l=strlen(s+1);i<=l;i++){
    			if(trans[now][s[i]-'0']) now=trans[now][s[i]-'0'];
    			else return -1;
    		}
    		return pos[now];
    	}
    }sam;
    int main()
    {
    	cin>>n;
    	scanf("%s",s+1);
    	for(int i=1;i<=n;i++) sam.insert(s[i]-'0',i);
    	sam.get_right();
    	cin>>m;
    	while(m--){
    		int ans=0;
    		scanf("%s",s+1);
    		int l=strlen(s+1),h=sam.check();
    		if(h==-1) ans=n;
    		else ans=h+1-l;
    		for(int i=1,now=1;i<l;i++){
    			if(sam.trans[now][s[i]-'0']) now=sam.trans[now][s[i]-'0'];
    			else break;
    			if(h==-1) ans+=query(T[now],1,n,1,n);
    			else ans+=query(T[now],1,n,1,h-l+i);
    		}
    		printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    Docker最全教程之使用Tencent Hub来完成CI(九)
    程序员十大热门flag,有你的吗?
    互联网寒冬,阿里Ant Design还开坑,程序员该何去何从?
    Docker最全教程——从理论到实战(八)
    开源库Magicodes.Storage正式发布
    Docker最全教程——从理论到实战(七)
    开源库支付库Magicodes.Pay发布
    产品经理如何避免被程序员打?
    Docker最全教程——从理论到实战(六)
    如何解决input file 选取相同文件后,change事件不起作用解决方法
  • 原文地址:https://www.cnblogs.com/victorique/p/10575973.html
Copyright © 2011-2022 走看看