https://nanti.jisuanke.com/t/4
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=6e5+10,base =131; 4 typedef unsigned long long ull; 5 char str[N]; 6 ull hl[N],hr[N],p[N]; 7 8 int mark[N][30]; 9 10 11 ull get(ull h[],int l,int r) 12 { 13 return h[r]-h[l-1]*p[r-l+1]; 14 } 15 16 int k=0; 17 long long getval(int l,int r) 18 { 19 if(l==r&&str[r]=='z'+1) 20 return 0; 21 long long sum=0; 22 if(str[l]=='z'+1) 23 l++; 24 for(int i=1;i<=26;++i) 25 { 26 int temp=(mark[r][i]-l+2)/2; 27 if(temp<0) 28 continue; 29 sum+=temp; 30 } 31 return sum; 32 } 33 int main() 34 { 35 36 37 cin>>(str+1); 38 int n=strlen(str+1); 39 40 for(int i=n*2;i>0;i-=2)//重点i-=2 模拟kmp添加一个字符 41 { 42 str[i]=str[i/2]; 43 str[i-1]='z'+1; 44 //中间插一个不需要的数 45 } 46 47 n=2*n; 48 p[0]=1; 49 for(int i=1;i<=n;++i) 50 { 51 for(int j=1;j<=26;++j) 52 { 53 mark[i][j]=mark[i-1][j]; 54 if(str[i]!='z'+1) 55 mark[i][str[i]-'a'+1]=i; 56 } 57 } 58 for(int i=1,j=n;i<=n;i++,j--) 59 { 60 hl[i]=hl[i-1]*base+str[i]-'a'+1;//正序的哈希值 -> 61 hr[i]=hr[i-1]*base+str[j]-'a'+1;//逆序的哈希值 -> 这个是必要的 62 p[i]=p[i-1]*base; 63 } 64 65 66 long long ans=0; 67 for(int i=1;i<=n;i++)//枚举每一个字符作为中点 68 { 69 int l=0,r=min(i-1,n-i); 70 while(l<r) 71 { 72 int mid=l+r+1>>1;//半径长度 73 74 75 //if(get(hl,i-mid,i-1) != get(hl,i+1,i+mid) ) 76 //判读的确是左右区间的判断 但是 值却都是->方向的 77 //所以这个就是必须要有逆序的原因 78 79 if(get(hl,i-mid,i-1) !=get(hr,n-(i+mid)+1,n-(i+1)+1)) 80 { 81 //如果不符合 肯定是缩小半径 82 r=mid-1; 83 } 84 else l=mid; 85 } 86 ans+=getval(i-l,i); 87 } 88 printf("%lld ",ans); 89 return 0; 90 }
1389
解:
字符串hash二分跑回文串。