zoukankan      html  css  js  c++  java
  • bzoj 3413: 匹配

    题目

    还是(SAM)亲切

    题意看起来挺不好懂得,其实就是问你截止到完全匹配之前,(S)串的每个位置和(T)串的(lcp+1)之和

    既然是需要完全匹配的,所以我们肯定需要先找到这个(T)串在(S)串中第一次出现的位置在哪里

    最开始觉得可以直接建广义(SAM)之后直接树上倍增找到(T)串,但是空间就挂了

    但是突然就发现我们好像可以直接在(S)串的(SAM)里匹配这个(T),匹配完了我们用主席树查一下最小的(endpos)就好了

    之后再来做一遍匹配,匹配出每一个(T)的前缀在(S)中出现的次数,但是必须要满足的是出现的开始位置不大于完全匹配的开始位置,还是主席树维护就好了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define maxn 200005
    #define M 3000005
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    struct E{int v,nxt;}e[maxn];
    int len[maxn],endpos[maxn],son[maxn][10],fa[maxn],head[maxn],to[maxn],_to[maxn],sum[maxn],rt[maxn];
    int n,cnt=1,lst=1,m,__,U,num,tot;
    int l[M],r[M],d[M];
    char S[maxn>>1];
    inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
    void dfs(int x) {sum[x]=1;to[x]=++__,_to[__]=x;for(re int i=head[x];i;i=e[i].nxt) dfs(e[i].v),sum[x]+=sum[e[i].v];}
    inline void ins(int c,int o)
    {
    	int p=++cnt,f=lst; lst=p;
    	len[p]=len[f]+1,endpos[p]=o;
    	while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    	if(!f) {fa[p]=1;return;}
    	int x=son[f][c];
    	if(len[f]+1==len[x]) {fa[p]=x;return;}
    	int y=++cnt;
    	len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    	for(re int i=0;i<10;i++) son[y][i]=son[x][i];
    	while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    }
    int change(int pre,int x,int y,int pos)
    {
    	int root=++tot;
    	d[root]=d[pre]+1;
    	if(x==y) return root;
    	l[root]=l[pre],r[root]=r[pre];
    	int mid=x+y>>1;
    	if(pos<=mid) l[root]=change(l[pre],x,mid,pos);
    		else r[root]=change(r[pre],mid+1,y,pos);
    	return root;
    }
    int ask(int p1,int p2,int x,int y)
    {
    	if(x==y) return x;
    	int mid=x+y>>1;
    	if(d[l[p2]]-d[l[p1]]>0) return ask(l[p1],l[p2],x,mid);
    	return ask(r[p1],r[p2],mid+1,y);
    }
    inline int find(int x)
    {
    	int y=to[x]+sum[x]-1;x=to[x];
    	return ask(rt[x-1],rt[y],1,U);
    }
    int query(int p1,int p2,int x,int y,int pos)
    {
    	if(x==y) return d[p2]-d[p1];
    	int mid=x+y>>1;
    	if(pos<=mid) return query(l[p1],l[p2],x,mid,pos);
    	return d[l[p2]]-d[l[p1]]+query(r[p1],r[p2],mid+1,y,pos);
    }
    inline int Find(int x,int val)
    {
    	int y=to[x]+sum[x]-1;x=to[x];
    	return query(rt[x-1],rt[y],1,U,val);
    }
    int main()
    {
    	scanf("%d",&n),scanf("%s",S+1);U=n;scanf("%d",&m);
    	for(re int i=1;i<=n;i++) ins(S[i]-'0',i);
    	for(re int i=2;i<=cnt;i++) add(fa[i],i); dfs(1);
    	for(re int i=1;i<=cnt;i++) 
    	if(endpos[_to[i]]) rt[i]=change(rt[i-1],1,n,endpos[_to[i]]); else rt[i]=rt[i-1];
    	while(m--)
    	{
    		scanf("%s",S+1);n=strlen(S+1);
    		int now=1,t;
    		for(re int i=1;i<=n;i++){if(!now) break;now=son[now][S[i]-'0'];}
    		if(!now) t=0;else t=find(now); 
    		now=1;LL ans=0;
    		for(re int i=1;i<=n;i++)
    		{
    			now=son[now][S[i]-'0'];
    			if(!now) break;
    			if(t) ans+=Find(now,t-n+i);else ans+=Find(now,U);
    		}
    		if(!now) ans+=U;
    			else ans+=t-n;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JavaScript(js)的replace问题的解决
    如何让Log4net日志文件按每月归成一个文件夹,StaticLogFileName参数的用法
    点到线的距离计算公式
    如何写一个Python万能装饰器,既可以装饰有参数的方法,也可以装饰无参数方法,或者有无返回值都可以装饰
    Python如何动态的为对象添加方法或属性,__slots__用法
    Python生成器的用法,使用生成器灵活的生成斐波那契数列
    Python函数名做参数,闭包,装饰器
    Python迭代器的用法,next()方法的调用
    property用法,使Python中的get方法和set方法使用更简单
    python中for循环删除不全的问题
  • 原文地址:https://www.cnblogs.com/asuldb/p/10298912.html
Copyright © 2011-2022 走看看