码迷,mamicode.com
首页 > 其他好文 > 详细

! HAOI2018字串覆盖

时间:2020-04-01 13:15:21      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:return   新建   long   continue   ret   sdi   inf   for   告诉   

技术图片
技术图片
技术图片

心路历程

\(r-l<51\) 将两个字符串中间加入一个字符合并,做后缀数组,找到查询串的\(rk\)往前\(min(hei)>=r\)的串若为A串且贡献为正即可加入,对于每一个B的位置预处理,时间复杂度\(O(nlog_n+(r-l)n+q)\)

\(r-l>2000\)后缀自动机+线段树合并,倍增找到点,跳endpos,跳的次数不会太多

SOL

数据有点特别啊~

\(r-l\in[51,2000]\)和>2000做法一样,因为数据随机分布,且不多

第一类数据的方法不用那么复杂,不过貌似我那个方法还做不出来

\(f_{len,u,i}\)左起为u长度为len的字符串,接\(2^i\)个同样的字符串后下一个的左端点是多少,\(g\)表示权值是多少

\(hash\)判重

\(map<ull,queue<int>>q;\) 真好用(放函数里(每次都新建一个,因为放全局会产生很多对映射,会TLE&MLE )我不会告诉你我交了20次才发现

ques

怎么找到\(l-r\)字符串的对应位置?

先预处理出b中每个前缀的最后一个字符的位置,和最大长度是多少,然后直接倍增跳link即可

细节好多┭┮﹏┭┮

#pragma GCC optimize(fast)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c==‘-‘)f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4;
struct node{
	int len,link,nxt[26],cl;
}s[N<<1];
int siz,las;
inline void clear(){
	siz=1;las=0;
	s[0].len=0;
	s[0].link=-1;
}
inline void extend(int c){
	int cur=siz++,p;
	s[cur].len=s[las].len+1;
	for(p=las;p!=-1&&!s[p].nxt[c];p=s[p].link)
		s[p].nxt[c]=cur;
	if(p==-1){s[cur].link=0;las=cur;return;}
	int q=s[p].nxt[c];
	if(s[q].len==s[p].len+1){s[cur].link=q;las=cur;return;}
	int clo=siz++;
	s[clo]=s[q];
	s[clo].len=s[p].len+1;
	s[clo].cl=1;
	for(;p!=-1&&s[p].nxt[c]==q;p=s[p].link)
		s[p].nxt[c]=clo;
	s[cur].link=s[q].link=clo;
	las=cur;
}
#define lc ch[p][0]
#define rc ch[p][1]
int tot,ch[N*40][2],rt[N<<1];
void modify(int &p,int l,int r,int x){
	if(!p)p=++tot;
	if(l==r)return;
	int mid=l+r>>1;
	if(x<=mid)modify(lc,l,mid,x);
	else modify(rc,mid+1,r,x);
}
int merge(int x,int y){
	if(!x||!y)return x|y;
	int p=++tot;
	lc=merge(ch[x][0],ch[y][0]);
	rc=merge(ch[x][1],ch[y][1]);
	return p;
}
int query(int p,int l,int r,int ql,int qr){
	if(!p)return -1;
	if(l==r)return l;
	int mid=l+r>>1,ret=-1;
	if(ql<=l&&r<=qr){
		if(lc)return query(lc,l,mid,ql,qr);
		else if(rc) return query(rc,mid+1,r,ql,qr);
	}
	if(ql<=mid)ret=query(lc,l,mid,ql,qr);
	if(ret==-1&&mid<qr)ret=query(rc,mid+1,r,ql,qr);
	return ret;
}
int n,k,ton[N],rk[N<<1],jump[N<<1][20],endpos[N],endlen[N];
char sa[N],sb[N];
inline void sam_init(){
	clear();
	for(int i=1;i<=n;i++)extend(sa[i]-‘a‘);
	for(int i=1,p=0;i<siz;i++)
		if(!s[i].cl)modify(rt[i],1,n,++p);
	for(int i=1;i<siz;i++)ton[s[i].len]++;
	for(int i=1;i<=n;i++)ton[i]+=ton[i-1];
	for(int i=1;i<siz;i++)rk[ton[s[i].len]--]=i;
	for(int i=siz-1;i;i--)
		rt[s[rk[i]].link]=merge(rt[s[rk[i]].link],rt[rk[i]]);
	for(int i=1;i<siz;i++)jump[i][0]=s[i].link;
	for(int i=1;i<=18;i++)
		for(int j=1;j<siz;j++)
			jump[j][i]=jump[jump[j][i-1]][i-1];
	for(int i=1,p=0,c,len=0;i<=n;i++){
		c=sb[i]-‘a‘;
		if(s[p].nxt[c]){len++;p=s[p].nxt[c];}
		else{
			while(p!=-1&&!s[p].nxt[c])p=s[p].link;
			if(p==-1)p=len=0;
			else{len=s[p].len+1;p=s[p].nxt[c];}
		}
		endpos[i]=p;endlen[i]=len;
	} 
}
inline int samrun(int x,int len){
	if(endlen[x]<len)return -1;
	x=endpos[x];
	for(int i=18;i>=0;i--)
		if(s[jump[x][i]].len>=len)x=jump[x][i];
	return x;
}
#define ll long long
#define ull unsigned long long
ll ans[N],g[N][20];
int f[N][20];
struct ques{
	int id,u,v,l;
};
vector<ques>qus[52];
ull mi[N],hsh[N];
inline void gethash(){
	mi[0]=1;
	for(int i=1;i<=n;i++){
		mi[i]=mi[i-1]*131; 
		hsh[i]=hsh[i-1]+mi[i]*(sa[i]^48);
	}
}
inline void solve(int len){
	if(qus[len].empty())return;
	map<ull,queue<int>>q;//放里面,因为外面会产生很多对映射,会TLE&MLE 
	for(int i=1;i<=n;i++){
		static ull x;
		for(int j=0;j<=18;j++)f[i][j]=0; 
		if(i+len>n)continue;
		g[i][0]=k-i;
		x=(hsh[i+len]-hsh[i-1])*mi[n-i-len];
		while(!q[x].empty()&&q[x].front()<i-len){
			f[q[x].front()][0]=i;
			q[x].pop();
		}
		q[x].push(i);
	}
	for(int i=1;i<=18;i++)
		for(int j=1;j<=n;j++){
			f[j][i]=f[f[j][i-1]][i-1];
			g[j][i]=g[j][i-1]+g[f[j][i-1]][i-1];
		}
	for(auto x:qus[len]){
		static int p,w;
		x.v=min(k-1,x.v-len);
		if(x.u>x.v)continue;
		p=samrun(x.l+len,len+1);
		if(p==-1)continue;
		w=query(rt[p],1,n,x.u+len,x.v+len);
		if(w==-1)continue;
		w-=len;
		for(int i=18;i>=0;i--)
			if(f[w][i]&&f[w][i]<=x.v){
				ans[x.id]+=g[w][i];
				w=f[w][i];
			}
		ans[x.id]+=g[w][0];
	}
}
int main(){
	n=read();k=read();
	scanf("%s%s",sa+1,sb+1);
	sam_init();
	gethash();
	int Q=read(),x,y,l,r,p,w;
	for(int i=1;i<=Q;i++){
		x=read();y=read();l=read();r=read();
		if(r-l>50){
			p=samrun(r,r-l+1);
			if(p==-1)continue;
			x+=r-l;y=min(n,min(k-1+r-l,y));
			while(x<=y){
				w=query(rt[p],1,n,x,y);
				if(w==-1)break;
				ans[i]+=k-w+r-l;
				x=w+1+r-l;
			}
		}
		else qus[r-l].push_back((ques){i,x,y,l});
	}
	for(int i=0;i<=50;i++)solve(i);
	for(int i=1;i<=Q;i++)cout<<ans[i]<<"\n";
	return (0-0);
}

! HAOI2018字串覆盖

标签:return   新建   long   continue   ret   sdi   inf   for   告诉   

原文地址:https://www.cnblogs.com/aurora2004/p/12611686.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!