题:http://acm.hdu.edu.cn/showproblem.php?pid=6230
题意:求一个字符串中(长度<=5e5)中指定字符串个数;
指定字符串约束为:类似俩个回文串“镶嵌”,设有俩个回文串的回文中心位置分别为x和y(x<y),前者的回文半径涵盖的范围必须包含y ,同时后者的回文半径要包含x;
分析:
问题可以转化为这样的(x,y)的对数;
也就是在x回文半径范围( x,x+rl[x] ]内有多少个位置y满足y-rl[y]<=x;
在处理时,维护以x的约束条件“y-rl[y]>x”的单调队列,单调队列过程中持续加上(x,x+rl[x] ]间的贡献
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define pb push_back const int inf=0x3f3f3f3f; const ll INF=(1ll<<40); const int M=1e6+6; char s[M]; int rl[M],p[M]; struct BIT{ ll tr[M]; void init(){ memset(tr,0,sizeof(tr)); } void add(int x,ll c){ for(int i=x;i<M;i+=i&-i) tr[i]+=c; } ll sum(int x){ ll res=0; for(int i=x;i;i-=i&-i) res+=tr[i]; return res; } }bit; ///int evenrl[M]; void manacher(){ int len=strlen(s); for(int i=len;i>=0;i--) s[i*2+1]=s[i],s[i*2]='#'; int id,mx=0; int m=2*len+1; for(int i=1;i<m;i++){ if(mx>i) p[i]=min(p[2*id-i],mx-i); else p[i]=1; while(s[i-p[i]]==s[i+p[i]]&&i-p[i]>=0&&i+p[i]<m)++p[i]; if(i+p[i]>mx) id=i,mx=p[i]+i; if(s[i]!='#') rl[(i+1)/2]=(p[i]-1)/2;///奇数长的回文,长度不含回文中心 ///else evenrl[(i+1)/2]=(p[i]-1)/2;///偶数长的回文,位置为左半部分末尾,长度为回文串的一半 } } struct node{ int val,id; }a[M]; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s",s); int n=strlen(s); bit.init(); manacher(); for(int i=1;i<=n;i++){ a[i].id=i; a[i].val=i-rl[i]; } sort(a+1,a+1+n,[&](node A,node B){ return A.val<B.val; }); int x=1; ll ans=0; for(int i=1;i<=n;i++){ while(x<=n&&a[i].val>x){ ans+=bit.sum(x+rl[x])-bit.sum(x); x++; } bit.add(a[i].id,1); } while(x<=n){ ans+=bit.sum(x+rl[x])-bit.sum(x); x++; } printf("%lld ",ans); } return 0; }