题目分析:
好题!我们发现题目实际是要求出从某个左端点开始跑出去的BB型有多少个和从某个右端点开始跑出去的AA型有多少个。
发现这个问题是对称的,所以只考虑从左端点跑出去的BB型有多少个就可以了。
我们不妨考虑长度为$k$的BB型,那么我们把字符串每$k$个化成一个整体,然后如果从$i$开始存在一个长度为$k$的BB型,就等价于$i$开始这个整体的后缀等于下一个整体的后缀,下一个整体的后缀等于下下个整体的前缀,所以我们用哈希来求出最长后缀和最长前缀就可以做了。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 102000; 5 6 int n; 7 char str[maxn]; 8 int pre[maxn],suf[maxn]; // longest qianzhui longest houzhui 9 int f[maxn],g[maxn]; 10 11 namespace HASH{ 12 int ph[2][maxn],bs[2][maxn]; 13 const int base = 37; 14 const int mod1 = 1004535809,mod2 = 999911659; 15 void buildhash(){ 16 ph[0][1] = ph[1][1] = str[0]-'a'+1; 17 bs[0][0] = bs[1][0] = 1; 18 for(int i=1;i<n;i++){ 19 ph[0][i+1] = (1ll*base*ph[0][i]+str[i]-'a'+1)%mod1; 20 ph[1][i+1] = (1ll*base*ph[1][i]+str[i]-'a'+1)%mod2; 21 } 22 for(int i=1;i<=n;i++) bs[0][i]=1ll*bs[0][i-1]*base%mod1; 23 for(int i=1;i<=n;i++) bs[1][i]=1ll*bs[1][i-1]*base%mod2; 24 } 25 int pd(int l1,int r1,int l2,int r2){ 26 int z1=ph[0][r1+1]-1ll*bs[0][r1-l1+1]*ph[0][l1]%mod1;if(z1<0)z1+=mod1; 27 int z2=ph[1][r1+1]-1ll*bs[1][r1-l1+1]*ph[1][l1]%mod2;if(z2<0)z2+=mod2; 28 int y1=ph[0][r2+1]-1ll*bs[0][r2-l2+1]*ph[0][l2]%mod1;if(y1<0)y1+=mod1; 29 int y2=ph[1][r2+1]-1ll*bs[1][r2-l2+1]*ph[1][l2]%mod2;if(y2<0)y2+=mod2; 30 if(z1 == y1 && z2 == y2) return true; 31 else return false; 32 } 33 int maxlen(int st1,int st2,int dr){ 34 if(st2 >=n) return 0; 35 int tl=1,tr=(dr==0?st1+1:n-st2+1); 36 if(str[st1] != str[st2]) return 0; 37 while(tl < tr){ 38 int mid = (tl+tr+1)/2; 39 int l1,r1,l2,r2; 40 if(dr == 0){r1=st1,r2=st2;l1=st1-mid+1,l2=st2-mid+1;} 41 else{l1=st1,l2=st2;r1=st1+mid-1,r2=st2+mid-1;} 42 if(pd(l1,r1,l2,r2)) tl = mid; 43 else tr = mid-1; 44 } 45 return tl; 46 } 47 } 48 49 50 void init(){ 51 memset(pre,0,sizeof(pre)); 52 memset(suf,0,sizeof(suf)); 53 memset(HASH::ph,0,sizeof(HASH::ph)); 54 memset(f,0,sizeof(f)); 55 memset(g,0,sizeof(g)); 56 } 57 58 void work(){ 59 HASH::buildhash(); 60 for(int i=1;i<=n/2;i++){ 61 int k = 0; 62 for(int j=0;j<n;j+=i){ 63 k++; 64 if(j+i < n){pre[k] = min(i,HASH::maxlen(j,j+i,1));} 65 if(j-i >=0){suf[k] = min(i,HASH::maxlen(j-1,j+i-1,0));} 66 } 67 for(int j=2,st=i;j<=k;j++,st+=i){ 68 if(pre[j] + suf[j] < i || suf[j] == 0) continue; 69 int l = st-suf[j],r = min(st-1,(st-i)+pre[j]); 70 f[l]++; f[r+1]--; 71 } 72 for(int j=1,st=0;j<k;j++,st+=i){ 73 if(pre[j] + suf[j] < i || pre[j] == 0) continue; 74 int l = max(st+i,(st+i-1+(i-suf[j]))),r = (st+i-1+pre[j]); 75 g[l]++; g[r+1]--; 76 } 77 for(int j=1;j<=k;j++) pre[j] = suf[j] = 0; 78 } 79 for(int i=1;i<n;i++) f[i] = f[i-1] + f[i]; 80 for(int i=1;i<n;i++) g[i] = g[i-1] + g[i]; 81 long long ans = 0; 82 for(int i=1;i<n;i++){ans += 1ll*f[i]*g[i-1];} 83 printf("%lld ",ans); 84 } 85 86 int main(){ 87 int Tmp; scanf("%d",&Tmp); 88 while(Tmp--){ 89 init(); 90 scanf("%s",str); 91 n = strlen(str); 92 work(); 93 } 94 return 0; 95 }