zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    可以使用多少列创建索引?
    如何显示前 50 行?
    简单描述 MySQL 中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响-从读写两方面?
    实践中如何优化 MySQL ?
    列的字符串类型可以是什么?
    MySQL 里记录货币用什么字段类型好 ?
    什么是通用 SQL 函数?
    对于关系型数据库而言,索引是相当重要的概念?
    为表中得字段选择合适得数据类型?
    SQL 注入漏洞产生的原因?如何防止?
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12611686.html
Copyright © 2011-2022 走看看