【CCPC2017哈尔滨A】Palindrome
原题:
题中那个奇怪的式子其实就表示一个三段对称的回文串
那用马拉车求出所有回文串及半径,问题就转化为有多少个回文串的中点i和j,使得|i-j|<=min{r[i],r[j]}
可以按照r递减的顺序枚举,这样只需考虑当前枚举到的回文串内有多少个已枚举过的回文串
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 struct nds{int x,y;}b[510000]; 7 int n; char s[510000]; 8 char ss[1100000]; 9 int f[1100000]; 10 int ar[510000]; 11 int v[510000]; 12 inline int lbt(int x){ return x&-x;} 13 int qry(int x){ 14 int bwl=0; 15 while(x) bwl+=v[x],x-=lbt(x); 16 return bwl; 17 } 18 void mdf(int x){while(x<=n) v[x]++,x+=lbt(x);} 19 void mlc(){ 20 for(int i=0;i<n;++i) ss[i<<1]='#',ss[i<<1|1]=s[i]; 21 int nn=n<<1; ss[nn]='#'; 22 int mx=0,id=0; 23 for(int i=0;i<=nn;++i){ 24 f[i]=(mx>i) ? min(f[2*id-i],mx-i) : 1; 25 while(i>=f[i] && i+f[i]<=nn && ss[i+f[i]]==ss[i-f[i]]) ++f[i]; 26 if(mx<i+f[i]-1) mx=i+f[i]-1,id=i; 27 } 28 for(int i=0;i<n;++i) ar[i]=f[i<<1|1]/2-1; 29 //for(int i=0;i<n;++i) cout<<ar[i]<<" "; 30 //cout<<endl; 31 } 32 bool cmp(nds x,nds y){ 33 return x.x==y.x ? x.y<y.y : x.x<y.x; 34 } 35 void prvs(){ 36 for(int i=0;i<=n;++i) v[i]=0; 37 } 38 int main(){ 39 int T; cin>>T; 40 while(T --> 0){ 41 scanf("%s",s); n=strlen(s); 42 prvs(); 43 mlc(); 44 for(int i=0;i<n;++i){ 45 //b[i]=(nds){ar[i],i+1}; 46 b[i].x=ar[i]; 47 b[i].y=i+1; 48 } 49 sort(b,b+n,cmp); 50 long long cnt=0; 51 for(int i=n-1;i>=0;--i){ 52 cnt+=qry(min(n,b[i].y+b[i].x))-qry(max(1,b[i].y-b[i].x)-1); 53 mdf(b[i].y); 54 } 55 printf("%lld\n",cnt); 56 } 57 return 0; 58 }