1 条题解

  • 0
    @ 2026-4-23 20:12:26

    刚刚发现赛时 manacher pp 数组没清空,气笑了。

    根据 P3546 中的 trick,将字符串变为 s1sns2sn1...s_1s_ns_2s_{n-1}... 后,border 变为开头的回文串。发现这题 [l,r][l,r] 从中心向两边拓展实际上为在字符串开头添加两个字符,所以转化后成了以正串中字符开头的偶回文串。比较特殊的是这题 border 能跨过中点,P3546 不行,只需要改一下,将完整的正反串交替,只查询前半部分表示 border 开头必须在前半部分即可。

    数据范围支持每次跑一遍 manacher,所以 O(nq)O(nq) 即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define mp make_pair
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
    #define ll long long
    inline int lowbit(int x){return x&-x;}
    const int N=4e6+5;
    int p[N];ll c[N],ans;
    inline void manacher(string t){
    	string s="^";
    	for(int i=0;i<t.size();i++)
    		s+='$',s+=t[i];
    	s+="$)";
    	int id,R=0,len=s.size();
    	for(int i=1;i<len;i++){
    		p[i]=1;
    		if(i<=R)p[i]=min(p[(id<<1)-i],R-i+1);
    		int l=i-p[i],r=i+p[i];
    		while(s[l]==s[r])--l,++r,++p[i];
    		if(i+p[i]-1>R)R=i+p[i]-1,id=i;
    	}
    	for(int i=1;i<=len/2;i+=2)
    		++c[i-p[i]+1],--c[i];
    	for(int i=1;i<=len/2;i++){
    		c[i]+=c[i-1];
    		if(!(i&1)&&((i>>1)&1))ans+=c[i];
    	}
    	for(int i=0;i<len/2;i++)c[i]=0;
    }
    inline void UesugiErii(){
    	int n,q;string s;
    	cin>>n>>q>>s,s=' '+s;
    	while(q--){
    		int k,l,r,x,y;string tmp="";
    		cin>>k;
    		if(k&1)y=(k+1)/2,x=y-1;
    		else x=k/2-1,y=k/2+1; 
    		for(l=x,r=y;l>=1&&r<=n;--l,++r);++l,--r;
    		for(int i=l,j=r;i<=r;++i,--j)tmp+=s[i],tmp+=s[j];
    		ans=0,manacher(tmp);
    		cout<<ans<<'\n';
    	}
    }
    /*
    9 6
    bbabbbbaa
    2
    5
    10
    11
    14
    15
    */ 
    signed main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	cfast;int _=1;//cin>>_;
    	for(;_;_--)UesugiErii();
    	return 0;
    }
    
    • 1

    信息

    ID
    9680
    时间
    500ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者