! HAOI2018字串覆盖

Posted aurora2004

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了! HAOI2018字串覆盖相关的知识,希望对你有一定的参考价值。

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

心路历程

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

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

SOL

数据有点特别啊~

(r-lin[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]<<"
";
	return (0-0);
}

以上是关于! HAOI2018字串覆盖的主要内容,如果未能解决你的问题,请参考以下文章

HAOI2014 遥感监测

「二分答案 + 搜索」[HAOI2007]覆盖问题

二分 贪心覆盖问题 BZOJ1052 HAOI2007

P2218 [HAOI2007]覆盖问题

[BZOJ]1052 覆盖问题(HAOI2007)

[HAOI2007]覆盖问题