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

    BZOJ3413: 匹配

    https://lydsy.com/JudgeOnline/problem.php?id=3413

    分析:

    • 这题很好啊。
    • 首先正着做比较麻烦,考虑转换一下。
    • 我们不求(S)中每个长度等于(m)的匹配长度而是求(T)中每个前缀会匹配多少次。
    • 这样就非常简单了,先跑一遍正常的匹配求在哪停止匹配。
    • 然后后缀树上线段树合并区间求和即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <set>
    using namespace std;
    typedef long long ll;
    #define N 200050
    #define db(x) cerr<<#x<<" = "<<x<<endl
    char w[N],str[N];
    int ch[N][10],fa[N],len[N],lst=1,cnt=1,flg[N],n,m;
    int root[N],yukari;
    int ls[N*20],rs[N*20],siz[N*20],ke[N],ro[N];
    void update(int l,int r,int x,int &p) {
    	if(!p) p=++yukari;
    	siz[p]++;
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	if(x<=mid) update(l,mid,x,ls[p]);
    	else update(mid+1,r,x,rs[p]);
    }
    int merge(int x,int y) {
    	if(!x||!y) return x+y;
    	int p=++yukari;
    	ls[p]=merge(ls[x],ls[y]);
    	rs[p]=merge(rs[x],rs[y]);
    	siz[p]=siz[ls[p]]+siz[rs[p]];
    	return p;
    }
    int query(int l,int r,int x,int y,int p) {
    	if(!p||!siz[p]||x>y) return 0;
    	if(x<=l&&y>=r) return siz[p];
    	int mid=(l+r)>>1,re=0;
    	if(x<=mid) re+=query(l,mid,x,y,ls[p]);
    	if(y>mid) re+=query(mid+1,r,x,y,rs[p]);
    	return re;
    }
    void insert(int x,int id) {
    	int p=lst,np=++cnt,q,nq;
    	len[np]=len[p]+1; flg[np]=id; lst=np;
    	for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
    	if(!p) fa[np]=1;
    	else {
    		q=ch[p][x];
    		if(len[q]==len[p]+1) fa[np]=q;
    		else {
    			nq=++cnt; len[nq]=len[p]+1; flg[nq]=flg[q];
    			fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			fa[np]=fa[q]=nq;
    			for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
    		}
    	}
    }
    int main() {
    	scanf("%d%s",&n,w+1);
    	int i;
    	for(i=1;i<=n;i++) insert(w[i]-'0',i),update(1,n,i,root[lst]);
    	for(i=1;i<=cnt;i++) ke[len[i]]++;
    	for(i=1;i<=cnt;i++) ke[i]+=ke[i-1];
    	for(i=cnt;i;i--) ro[ke[len[i]]--]=i;
    	for(i=cnt;i>1;i--) {
    		int p=ro[i];
    		root[fa[p]]=merge(root[fa[p]],root[p]);
    	}
    	int cas;
    	scanf("%d",&cas);
    	while(cas--) {
    		scanf("%s",str+1);
    		m=strlen(str+1);
    		int p=1,flag=1;
    		for(i=1;i<=m;i++) {
    			int x=str[i]-'0';
    			if(ch[p][x]) {
    				p=ch[p][x];
    			}else {
    				flag=0; break;
    			}
    		}
    		ll ans=0;
    		int pos=flg[p];
    		if(!flag) pos=n,ans=n;
    		else ans=pos-m;
    		p=1;
    		for(i=1;i<=m;i++) {
    			int x=str[i]-'0';
    			if(ch[p][x]) {
    				p=ch[p][x];
    				if(!flag) ans+=query(1,n,1,n,root[p]);
    				else ans+=query(1,n,1,pos-(m-i),root[p]);
    			}else break;
    		}
    		printf("%lld
    ",ans);
    	}
    }
    
  • 相关阅读:
    软件工程第一次作业
    邮件服务器的搭建
    将博客搬至CSDN
    古典密码加密解密之多表代换
    Nginx + Tomcat 负载均衡配置详解
    openstack i版搭建教程
    IIS、apache、tomcat服务器虚拟主机配置
    SMTP邮件发送命令
    hadoop集群安装
    信息管理系统(java)
  • 原文地址:https://www.cnblogs.com/suika/p/10205842.html
Copyright © 2011-2022 走看看