[xsy2242]回文子串

Posted jefflyy

tags:

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

题意:给定参数$k$,维护一个字符串,支持区间覆盖字符和查询,查询是查询区间中有多少个长度$leq k$的子串是回文串,其中$kleq50$

$k$很小,考虑从这里入手,我们先用manacher预处理出以每个位置开头有多少个回文串,用线段树存起来

查询$[l,r]$时$[l,r-k+1]$这段可以直接解区间求和,剩下那段单独拿出来做manacher

修改$[l,r]$时$[l,r-k+1]$这段全部变成$k$,把$[l-k+1,l+k-2]$这段拿出来做manacher更新$[l-k+1,l-1]$的值,把$[r-k+2,r+k-1]$这段拿出来做manacher更新$[r-k+2,r]$的值

然而我不会写manacher而且时限很大,所以直接哈希就可以了

#include<stdio.h>
#include<string.h>
typedef unsigned long long ll;
const ll ba=19260817;
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
ll fh[50010],bh[50010],b[50010];
ll getf(int l,int r){return fh[r]-fh[l-1]*b[r-l+1];}
ll getb(int l,int r){return bh[l]-bh[r+1]*b[r-l+1];}
int k;
void getpa(char*s,int*c){
	int n,i,l,r,mid,ans;
	n=strlen(s+1);
	memset(c,0,(n+1)<<2);
	b[0]=1;
	fh[0]=0;
	for(i=1;i<=n;i++){
		b[i]=b[i-1]*ba;
		fh[i]=fh[i-1]*ba+s[i];
	}
	bh[n+1]=0;
	for(i=n;i>0;i--)bh[i]=bh[i+1]*ba+s[i];
	for(i=1;i<=n;i++){
		l=1;
		r=min(i,n-i+1);
		while(l<=r){
			mid=(l+r)>>1;
			if(getf(i-mid+1,i)==getb(i,i+mid-1)){
				ans=mid;
				l=mid+1;
			}else
				r=mid-1;
		}
		if(ans>(k+1)/2)ans=(k+1)/2;
		c[i-ans+1]++;
		c[i+1]--;
	}
	for(i=1;i<n;i++){
		l=1;
		r=min(i,n-i);
		ans=0;
		while(l<=r){
			mid=(l+r)>>1;
			if(getf(i-mid+1,i)==getb(i+1,i+mid)){
				ans=mid;
				l=mid+1;
			}else
				r=mid-1;
		}
		if(ans>k/2)ans=k/2;
		c[i-ans+1]++;
		c[i+1]--;
	}
	for(i=1;i<=n;i++)c[i]+=c[i-1];
}
struct segi{
	int s[200010],t[200010];
	void cov(int x,int len,int v){
		s[x]=len*v;
		t[x]=v;
	}
	void pushdown(int x,int ln,int rn){
		if(t[x]){
			cov(x<<1,ln,t[x]);
			cov(x<<1|1,rn,t[x]);
			t[x]=0;
		}
	}
	void pushup(int x){s[x]=s[x<<1]+s[x<<1|1];}
	void modify(int L,int R,int v,int l,int r,int x){
		if(L<=l&&r<=R)return cov(x,r-l+1,v);
		int mid=(l+r)>>1;
		pushdown(x,mid-l+1,r-mid);
		if(L<=mid)modify(L,R,v,l,mid,x<<1);
		if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
		pushup(x);
	}
	int query(int L,int R,int l,int r,int x){
		if(L<=l&&r<=R)return s[x];
		int mid=(l+r)>>1,t=0;
		pushdown(x,mid-l+1,r-mid);
		if(L<=mid)t+=query(L,R,l,mid,x<<1);
		if(mid<R)t+=query(L,R,mid+1,r,x<<1|1);
		return t;
	}
}ti;
struct segc{
	char c[200010];
	void pushdown(int x){
		if(c[x]){
			c[x<<1]=c[x<<1|1]=c[x];
			c[x]=0;
		}
	}
	void modify(int L,int R,char v,int l,int r,int x){
		if(L<=l&&r<=R){
			c[x]=v;
			return;
		}
		pushdown(x);
		int mid=(l+r)>>1;
		if(L<=mid)modify(L,R,v,l,mid,x<<1);
		if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
	}
	char query(int p,int l,int r,int x){
		if(l==r)return c[x];
		int mid=(l+r)>>1;
		pushdown(x);
		if(p<=mid)
			return query(p,l,mid,x<<1);
		else
			return query(p,mid+1,r,x<<1|1);
	}
}tc;
char s[50010];
int tmp[50010],n;
int main(){
	int m,i,j,x,y,ans;
	scanf("%s%d%d",s+1,&k,&m);
	n=strlen(s+1);
	for(i=1;i<=n;i++)tc.modify(i,i,s[i],1,n,1);
	getpa(s,tmp);
	for(i=1;i<=n;i++)ti.modify(i,i,tmp[i],1,n,1);
	while(m--){
		scanf("%d%d%d",&i,&x,&y);
		if(i==1){
			scanf("%s",s);
			tc.modify(x,y,s[0],1,n,1);
			if(y-x+1>=k)ti.modify(x,y-k+1,k,1,n,1);
			for(i=max(1,x-k+1),j=1;i<=min(n,x+k-2);i++,j++)s[j]=tc.query(i,1,n,1);
			s[j]=0;
			getpa(s,tmp);
			for(i=max(1,x-k+1),j=1;i<x;i++,j++)ti.modify(i,i,tmp[j],1,n,1);
			for(i=max(1,y-k+2),j=1;i<=min(y+k-1,n);i++,j++)s[j]=tc.query(i,1,n,1);
			s[j]=0;
			getpa(s,tmp);
			for(i=max(1,y-k+2),j=1;i<=y;i++,j++)ti.modify(i,i,tmp[j],1,n,1);
		}else{
			ans=0;
			if(y-x+1>=k)ans+=ti.query(x,y-k+1,1,n,1);
			for(i=max(x,y-k+2),j=1;i<=y;i++,j++)s[j]=tc.query(i,1,n,1);
			s[j]=0;
			getpa(s,tmp);
			for(i=max(x,y-k+2),j=1;i<=y;i++,j++)ans+=tmp[j];
			printf("%d
",ans);
		}
	}
}

以上是关于[xsy2242]回文子串的主要内容,如果未能解决你的问题,请参考以下文章

day 57 代码思想录 647. 回文子串 |

Manachar算法详解

算法竞赛入门经典 例题 3-4 回文串

华为机试题 HJ85最长回文子串

华为机试题 HJ85最长回文子串

最长回文字串暴力