洛谷 P9482 - [NOI2023] 字符串

从部分分考虑起。性质 A 看上去在很多字符串题里都有出现,因此我们从看上去比较奇怪的性质 B 入手。因为 \(\forall i\in[1,n-1],s_i\ne s_{i+1}\),所以 \(\forall l\in[1,r],s_{i+l}\ne s_{i+l-1}\),也就是说 \(s[i,i+l-1]\ne R(s[i+l,i+2l-1])\) 一定成立。这样我们考虑 \(T=S+\text{#}+R(S)\),求出 \(T\) 每个后缀的排名,那么可以证明一组 \((i,l)\) 合法当且仅当 \(rk_i<rk_{2n+1-(i+2l-1)+1}\)(也即,以 \(i\) 开始的后缀小于以 \(i+2l-1\) 结尾的前缀)。离线下来树状数组维护可以解决性质 B。

接下来考虑原问题。我们先套用性质 B 的做法求一下每一组询问的答案,然后考虑那些需要特殊处理的,即 \(s[i,i+l-1]=R(s[i+l,i+2l-1])\) 并且 \(rk_i<rk_{2n+1-(i+2l-1)+1}\)\((i,l)\)。考虑枚举这个回文中心,假设位于 \(i\)\(i+1\) 之间,然后你发现一个性质就是以这个位置为回文中心的所有回文串的所有回文串 \([l,r]\),它们的 \([s[l...n]<R(s[1...r])]\),要么同为真要么同为假,因此这样一来我们考虑扣掉的贡献是什么:如果 \(s[i,i+l-1]=R(s[i+l,i+2l-1])\)\(i+l-1\) 对应的上述布尔值为真,那么我们就要将答案减去 \(1\)。我们求出 \(\text{LCP}(s[i+1...n],R(s[1...i]))\),这样问题转化为斜线 \(+1\),查询一个竖直线段上的值之和。同样可以树状数组解决。

时间复杂度 \(O(n\log n)\)

const int MAXN=1e5;
const int LOG_N=18;
int n,qu,len,res[MAXN+5];char s[MAXN*2+5],t[MAXN*2+5];
int sa[MAXN*2+5],rk[MAXN*2+5],ht[MAXN*2+5],buc[MAXN*2+5],seq[MAXN*2+5];
int st[LOG_N+2][MAXN*2+5],lg[MAXN*2+5];
void getsa(){
	memset(sa,0,sizeof(sa));memset(rk,0,sizeof(rk));
	memset(ht,0,sizeof(ht));memset(buc,0,sizeof(buc));
	int vmax=122,gr=0;
	for(int i=1;i<=len;i++)buc[t[i]]++;
	for(int i=1;i<=vmax;i++)buc[i]+=buc[i-1];
	for(int i=len;i;i--)sa[buc[t[i]]--]=i;
	for(int i=1;i<=len;i++){
		if(t[sa[i]]!=t[sa[i-1]])++gr;
		rk[sa[i]]=gr;
	}vmax=gr;
	for(int k=1;k<=len;k<<=1){
		static pii x[MAXN*2+5];
		for(int i=1;i<=len;i++){
			if(i+k<=len)x[i]=mp(rk[i],rk[i+k]);
			else x[i]=mp(rk[i],0);
		}memset(buc,0,sizeof(buc));gr=0;int num=0;
		for(int i=len-k+1;i<=len;i++)seq[++num]=i;
		for(int i=1;i<=len;i++)if(sa[i]>k)seq[++num]=sa[i]-k;
		for(int i=1;i<=len;i++)buc[x[i].fi]++;
		for(int i=1;i<=vmax;i++)buc[i]+=buc[i-1];
		for(int i=len;i;i--)sa[buc[x[seq[i]].fi]--]=seq[i];
		for(int i=1;i<=len;i++){
			if(x[sa[i]]!=x[sa[i-1]])++gr;
			rk[sa[i]]=gr;
		}vmax=gr;if(vmax==len)break;
	}
}
void getht(){
	int k=0;
	for(int i=1;i<=len;i++){
		if(rk[i]==1)continue;if(k)--k;int j=sa[rk[i]-1];
		while(i+k<=len&&j+k<=len&&t[i+k]==t[j+k])++k;
		ht[rk[i]]=k;
	}
}
void buildst(){
	for(int i=1;i<=len;i++)st[0][i]=ht[i];
	for(int i=1;i<=LOG_N;i++)for(int j=1;j+(1<<i)-1<=len;j++)
		st[i][j]=min(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
int query_st(int l,int r){int k=lg[r-l+1];return min(st[k][l],st[k][r-(1<<k)+1]);}
int getlcp(int x,int y){
	if(x==y)return len-x+1;x=rk[x];y=rk[y];
	if(x>y)swap(x,y);return query_st(x+1,y);
}
vector<pii>qv[MAXN+5];vector<int>pv[MAXN+5];
struct fenwick{
	int t[MAXN*2+5];
	void init(){memset(t,0,sizeof(t));}
	void add(int x,int v){for(int i=x;i<=len;i+=(i&(-i)))t[i]+=v;}
	int query(int x){int ret=0;for(int i=x;i;i&=(i-1))ret+=t[i];return ret;}
}T[2],tt;
void solve(){
	scanf("%d%d%s",&n,&qu,s+1);len=0;memset(t,0,sizeof(t));
	for(int i=1;i<=n;i++)t[++len]=s[i];t[++len]='#';
	for(int i=n;i;i--)t[++len]=s[i];
	getsa();getht();buildst();
	for(int i=1;i<=n;i++)qv[i].clear();memset(res,0,sizeof(res));
	for(int i=1,x,y;i<=qu;i++)scanf("%d%d",&x,&y),qv[x].pb(mp(y,i));
	T[0].init();T[1].init();
	for(int i=len;i;i--){
		if(sa[i]>n+1){
			int pos=len-sa[i]+1;
			T[pos&1].add(pos,1);
		}else if(sa[i]<=n){
			int pos=sa[i];
			for(pii p:qv[pos])res[p.se]=T[(pos&1)^1].query(pos+2*p.fi-1)-T[(pos&1)^1].query(pos-1);
		}
	}
	for(int i=1;i<=n+1;i++)pv[i].clear();
	for(int i=1;i<n;i++){
		int L=getlcp(i+1,len-i+1);
//		printf("! %d %d\n",i,L);
		if(rk[i-L+1]<rk[len-(i+L)+1]&&L)pv[i-L+1].pb(i);
	}
	tt.init();
	for(int i=1;i<=n;i++){
		for(int x:pv[i])tt.add(x,1);
		for(pii p:qv[i])res[p.se]-=tt.query(i+p.fi-1)-tt.query(i-1);
	}
	for(int i=1;i<=qu;i++)printf("%d\n",res[i]);
}
int main(){
	for(int i=2;i<=MAXN*2;i++)lg[i]=lg[i>>1]+1;
	int qu;scanf("%*d%d",&qu);while(qu--)solve();
	return 0;
}

posted @ 2023-08-01 23:55  tzc_wk  阅读(94)  评论(0编辑  收藏  举报