LOJ 6031 「雅禮集訓 2017 Day1」字符串

題目大意:給定模板串ss,和一個長度爲mm的詢問序列,每個詢問操作爲把詢問串的llrr的子串在模板串中的出現次數,共QQ個真正的詢問,每個會給定一個長度爲kk的串,問操作[L,R][L,R]的詢問答案之和。
s,m,q×k105|s|,m,q\times k\leq 10^5
做法:對題目稍加觀察,q×kq\times k10510^5的數據範圍有明顯提示,可以確定根據kkm\sqrt m的關係進行數據分治,對於kmk\leq \sqrt m的,具有的特點是每個詢問的串長小,這樣就可以對每一個後綴直接插入SAMSAM進行詢問。而k>mk>\sqrt m時,特點爲qq較小,可以直接把對應詢問序列裏面的詢問拆解,逐個詢問。而對於出現多少次,可以把模板串和詢問串放在一起建SASA,每次找到區間最小值分治。這樣我們按照詢問長度從大到小的順序詢問,在詢問長度減小的過程中會不斷有分治的區間合併。採用分塊的方式來區間加單點求和。
時間複雜度:O(qkm)O(qk\sqrt m)
感覺有很多更簡潔的做法,我寫了5k。還是太菜了,下次希望想一點簡便的做法。
代碼:

#include<iostream>
#include<cstring>
#include<cassert>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<time.h>
#include<bitset>
#include<cstdio>
#include<algorithm>
using namespace std;
#define REP(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) REP(i,1,n)
#define rep0(i,n) REP(i,0,n-1)
#define repG(i,x) for(int i=pos[x];~i;i=e[i].next)
#define ll long long
#define db double
const int N=3e5+7;
const int INF=1e9+7;
namespace seg{
	const int T=320;
	int tg[N],a[N];
	void ins(int L,int R,int v){
		if(L/T==R/T){
			REP(i,L,R)a[i]+=v;
			return;
		}
		while(L%T!=0)a[L++]+=v;
		a[R]+=v;
		while(R%T!=0)a[--R]+=v;
		REP(i,L/T,R/T-1)tg[i]+=v;
	}
	int check(int x){return a[x]+tg[x/T];}
}
namespace SA{
	int n,cnt;
	int a[N],sa[N],ra[N],ns[N],nr[N],ls[N],ct[N],nw[N],mn[N*2],sm[N];
	char s[N];
	struct pir{int x,v;}p[N],h[N][22];
	pir mer(pir a,pir b){return (a.v<b.v)?a:b;}
	bool cmp(pir a,pir b){return a.v<b.v;}
	struct tri{int x,l,r,v;}t[N*2];
	bool cmp2(tri a,tri b){return a.x>b.x;}
	pir check(int L,int R){
		int k=mn[R-L+1];
		return mer(h[L][k],h[R-(1<<k)+1][k]);
	}
	void solve(int l,int r){
		if(l==r)return;
		pir o=check(l,r-1);
		t[++cnt]=(tri){o.v,l,o.x,sm[r]-sm[o.x]};
		t[++cnt]=(tri){o.v,o.x+1,r,sm[o.x]-sm[l-1]};
		if(!r)return;
		solve(l,o.x);
		solve(o.x+1,r);
	}
	void wk(){
		rep(i,n)p[i]=(pir){i,a[i]};
		sort(p+1,p+n+1,cmp);
		int las=1;
		rep(i,n){
			if(p[i].v!=p[i-1].v)las=i;
			ra[p[i].x]=las;
			sa[i]=p[i].x;
		}
		for(int i=1;i<n;i<<=1){
			rep(j,n)ct[j]=ls[j]=nw[j]=-1;
			REP(j,n-i+1,n){
				nw[ra[j]]++;
				ns[ra[j]]=j;
				nr[j]=ra[j];
			}
			rep(j,n){
				if(sa[j]<=i)continue;
				int p=sa[j]-i;
				nw[ra[p]]++;
				if(ra[sa[j]]!=ct[ra[p]]){
					ct[ra[p]]=ra[sa[j]];
					ls[ra[p]]=nw[ra[p]];
				}
				ns[ra[p]+nw[ra[p]]]=p;
				nr[p]=ra[p]+ls[ra[p]];
			}
			rep(j,n)sa[j]=ns[j],ra[j]=nr[j];
		}
		int ans=0;
		rep(i,n){
			if(ra[i]==n){
				ans=0;
				continue;
			}
			if(ans)ans--;
			int p=sa[ra[i]+1];
			while(a[p+ans]==a[i+ans]&&i+ans<=n&&p+ans<=n)ans++;
			h[ra[i]][0]=(pir){ra[i],ans};
		}
		for(int i=1;(1<<i)<n;i++){
			rep(j,n-(1<<i))h[j][i]=mer(h[j][i-1],h[j+(1<<(i-1))][i-1]);
			REP(j,(1<<i)+1,(1<<(i+1)))mn[j]=i;
		}
	}
	void init(int *b,int nn,int gg){
		n=nn;
		cnt=0;
		rep(i,n)a[i]=b[i];
		wk();
		rep(i,gg)sm[ra[i]]++;
		rep(i,n)sm[i]+=sm[i-1];
		solve(1,n);
		sort(t+1,t+cnt+1,cmp2);
	}
}
int n,m,Q,K;
namespace D1{
	int L[N],R[N],wa[N],bg[N],u[N],v[N],p[N];
	ll Ans[N];
	int cnt,tot;
	char s[N];
	vector<int>g[N];
	bool cmp(int x,int y){return (R[x]-L[x])>(R[y]-L[y]);}
	void solve(){
		scanf("%s",s+1);
		cnt=tot=0;
		rep(i,n)wa[++cnt]=s[i]-'a';
		rep(i,m)scanf("%d%d",&L[i],&R[i]);
		rep(i,m)L[i]++,R[i]++;
		rep(i,Q){
			scanf("%s%d%d",s+1,&u[i],&v[i]);
			u[i]++;
			v[i]++;
			wa[++cnt]=-1;
			bg[i]=cnt;
			rep(j,K)wa[++cnt]=s[j]-'a';
			REP(j,u[i],v[i])g[j].push_back(i);
		}
		SA::init(wa,cnt,n);
		rep(i,m)p[i]=i;
		sort(p+1,p+m+1,cmp);
		int nw=1;
		rep(i,m){
			while(nw<=SA::cnt&&SA::t[nw].x>=R[p[i]]-L[p[i]]+1){
				seg::ins(SA::t[nw].l,SA::t[nw].r,SA::t[nw].v);
				nw++;
			}
			for(int j=0;j<g[p[i]].size();j++){
				int d=g[p[i]][j];
				Ans[d]+=(ll)seg::check(SA::ra[bg[d]+L[p[i]]]);
			}
		}
		rep(i,Q)printf("%lld\n",Ans[i]);
	}
}
namespace D2{
	const int T=320;
	int L[N],R[N],sz[N],sm[T][T];
	char s[N],sv[N];
	vector<int>sg[N];
	struct sam{
		int p,l;
		int to[26];
	}t[N*2];
	int cnt,ls,tot;
	int ins(int x){
		t[++cnt].l=t[ls].l+1;
		int i=ls;
		ls=cnt;
		for(;i;i=t[i].p){
			if(t[i].to[x])break;
			t[i].to[x]=cnt;
		}
		if(!i){t[cnt].p=1; return ls;}
		int q=t[i].to[x];
		if(t[q].l==t[i].l+1){t[cnt].p=q; return ls;}
		t[++cnt]=t[q];
		t[cnt].l=t[i].l+1;
		t[ls].p=cnt;
		t[q].p=cnt;
		for(;i;i=t[i].p){
			if(t[i].to[x]!=q)break;
			t[i].to[x]=cnt;
		}
		return ls;
	}
	vector<int>E[N];
	void dfs(int x){
		for(int j=0;j<E[x].size();j++){
			dfs(E[x][j]);
			sz[x]+=sz[E[x][j]];
		}
	}
	struct pir{int x,v,d;}tt[N];
	bool cmp(pir u,pir v){return u.x<v.x;}
	void solve(){
		scanf("%s",s+1);
		cnt=ls=1;
		tot=0;
		rep(i,n)sz[ins(s[i]-'a')]++;
		REP(i,2,cnt)E[t[i].p].push_back(i);
		dfs(1);
		rep(i,m)scanf("%d%d",&L[i],&R[i]);
		rep(i,m)L[i]++,R[i]++;
		rep(i,Q){
			scanf("%s",s+1);
			rep(j,K){
				sv[(i-1)*K+j]=s[j];
				rep(k,K+1)sg[(i-1)*K+j].push_back(0);
			}
			int x,y; scanf("%d%d",&x,&y);
			x++; y++;
			if(x>1)tt[++tot]=(pir){x-1,-1,i};
			tt[++tot]=(pir){y,1,i};
		}
		sort(tt+1,tt+tot+1,cmp);
		int nw=1;
		rep(i,m){
			sm[L[i]][R[i]]++;
			while(nw<=tot&&tt[nw].x==i){
				rep(j,K)REP(k,j,K)sg[(tt[nw].d-1)*K+j][k]+=tt[nw].v*sm[j][k];
				nw++;
			}
		}
		rep(i,Q){
			ll ans=0;
			int bb=(i-1)*K;
			rep(j,K){
				int nw=1;
				REP(k,j,K){
					if(!t[nw].to[sv[bb+k]-'a'])break;
					nw=t[nw].to[sv[bb+k]-'a'];
					ans+=(ll)sg[bb+j][k]*sz[nw];
				}
			}
			printf("%lld\n",ans);
		}
	}
}
int main(){
	scanf("%d%d%d%d",&n,&m,&Q,&K);
	if(K*K>=m)D1::solve();
	else D2::solve();
	return 0;
}

由於疫情的原因,閒着也是閒着,就寫了這篇博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章