1 条题解
-
0
刚刚发现赛时 manacher 数组没清空,气笑了。
根据 P3546 中的 trick,将字符串变为 后,border 变为开头的回文串。发现这题 从中心向两边拓展实际上为在字符串开头添加两个字符,所以转化后成了以正串中字符开头的偶回文串。比较特殊的是这题 border 能跨过中点,P3546 不行,只需要改一下,将完整的正反串交替,只查询前半部分表示 border 开头必须在前半部分即可。
数据范围支持每次跑一遍 manacher,所以 即可。
#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
- 上传者