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\n",ans);
	}
}
posted @ 2019-01-01 20:21  fcwww  阅读(242)  评论(0编辑  收藏  举报