Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 433 Accepted Submission(s): 168
php
//要求的就是迴文半徑相互覆蓋的點對有多少,manacher預處理出來奇數長度迴文串的中間點的迴文半徑,用優先隊列記錄一下到達j點最遠可以覆 //蓋到的位置,當到達i位置時更新隊列(去掉沒有用了的點,即到達不了i位置的點),樹狀數組求i位置前半徑中有多少相互覆蓋的點並把i加入隊列。 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; typedef long long ll; const int MAXN=500009; char s[MAXN]; int t,n,p[MAXN<<2],a[MAXN<<2]; struct cmp{ bool operator () (int &a,int &b)const{ return a+p[a]>b+p[b]; } }; void manacher() { n=strlen(s+1); for(int i=1,mx=0,id=0;i<=n;i++){ p[i]=(mx>i?min(p[id*2-i],mx-i):1); while(s[i+p[i]]==s[i-p[i]]) p[i]++; if(i+p[i]>mx) { mx=i+p[i];id=i; } } for(int i=1;i<=n;i++) p[i]--; } void add(int id,int c) { while(id<=MAXN-9){ a[id]+=c; id+=((-id)&id); } } int query(int id) { int s=0; while(id){ s+=a[id]; id-=((-id)&id); } return s; } int main() { scanf("%d",&t); while(t--){ scanf("%s",s+1); manacher(); memset(a,0,sizeof(a)); ll ans=0; priority_queue<int,vector<int>,cmp>q; for(int i=2;i<=n;i++){ while(!q.empty()){ int now=q.top(); if(now+p[now]<i){ q.pop(); add(now,-1); }else break; } ans+=query(i-1)-query(i-p[i]-1); q.push(i);add(i,1); } printf("%lld\n",ans); } return 0; }