【CCPC2017哈尔滨A】Palindrome

原题:

【CCPC2017哈尔滨A】Palindrome_第1张图片

 

 

题中那个奇怪的式子其实就表示一个三段对称的回文串

那用马拉车求出所有回文串及半径,问题就转化为有多少个回文串的中点i和j,使得|i-j|<=min{r[i],r[j]}

可以按照r递减的顺序枚举,这样只需考虑当前枚举到的回文串内有多少个已枚举过的回文串

 

代码:

 1 #include
 2 #include
 3 #include
 4 #include
 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;i1]='#',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(mx1)  mx=i+f[i]-1,id=i;
27     }
28     for(int i=0;i1|1]/2-1;
29     //for(int i=0;i30     //cout<
31 }
32 bool cmp(nds x,nds y){
33     return x.x==y.x ? x.yy.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;ii){
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 }
View Code

 

你可能感兴趣的:(【CCPC2017哈尔滨A】Palindrome)