Description
如果一個字符串可以被拆分爲 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,則我們稱該字符串的這種拆
分是優秀的。例如,對於字符串 aabaabaa,如果令 A=aabA=aab,B=aB=a,我們就找到了這個字符串拆分成 AABBA
ABB 的一種方式。一個字符串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比如我們令 A=aA=a,B=baa
B=baa,也可以用 AABBAABB 表示出上述字符串;但是,字符串 abaabaa 就沒有優秀的拆分。現在給出一個長度爲
nn 的字符串 SS,我們需要求出,在它所有子串的所有拆分方式中,優秀拆分的總個數。這裏的子串是指字符串
中連續的一段。以下事項需要注意:出現在不同位置的相同子串,我們認爲是不同的子串,它們的優秀拆分均會被
記入答案。在一個拆分中,允許出現 A=BA=B。例如 cccc 存在拆分 A=B=cA=B=c。字符串本身也是它的一個子串。
Input
每個輸入文件包含多組數據。輸入文件的第一行只有一個整數 TT,表示數據的組數。保證 1≤T≤101≤T≤10。接
下來 TT 行,每行包含一個僅由英文小寫字母構成的字符串 SS,意義如題所述。
Output
輸出 TT 行,每行包含一個整數,表示字符串 SS 所有子串的所有拆分中,總共有多少個是優秀的拆分。
Sample Input
4
aabbbb
cccccc
aabaabaabaa
bbaabaababaaba
Sample Output
3
5
4
7
我們用 S[i,j]S[i,j] 表示字符串 SS 第 ii 個字符到第 jj 個字符的子串(從 11 開始計數)。第一組數據中,
共有 33 個子串存在優秀的拆分:S[1,4]=aabbS[1,4]=aabb,優秀的拆分爲 A=aA=a,B=bB=b;S[3,6]=bbbbS[3,6]
=bbbb,優秀的拆分爲 A=bA=b,B=bB=b;S[1,6]=aabbbbS[1,6]=aabbbb,優秀的拆分爲 A=aA=a,B=bbB=bb。而剩
下的子串不存在優秀的拆分,所以第一組數據的答案是 33。第二組數據中,有兩類,總共 44 個子串存在優秀的
拆分:對於子串 S[1,4]=S[2,5]=S[3,6]=ccccS[1,4]=S[2,5]=S[3,6]=cccc,它們優秀的拆分相同,均爲 A=cA=c,
B=cB=c,但由於這些子串位置不同,因此要計算 33 次;對於子串 S[1,6]=ccccccS[1,6]=cccccc,它優秀的拆分
有 22 種:A=cA=c,B=ccB=cc 和 A=ccA=cc,B=cB=c,它們是相同子串的不同拆分,也都要計入答案。所以第二組
數據的答案是 3+2=53+2=5。第三組數據中,S[1,8]S[1,8] 和 S[4,11]S[4,11] 各有 22 種優秀的拆分,其中 S[1
,8]S[1,8] 是問題描述中的例子,所以答案是 2+2=42+2=4。第四組數據中,S[1,4]S[1,4],S[6,11]S[6,11],S[7
,12]S[7,12],S[2,11]S[2,11],S[1,8]S[1,8] 各有 11 種優秀的拆分,S[3,14]S[3,14] 有 22 種優秀的拆分,
所以答案是 5+2=75+2=7。
題解
這道題的思路確實挺神的,我們先枚舉AABB中A的長度i,然後在字符串上每隔i位設置一個關鍵點,看相鄰的兩個關鍵點最多能向左向右擴張多少,這裏可以二分哈希實現,這樣一個長度爲i的AA串就一定經過這兩個關鍵點,最後我們得到的是一個個區間,差分一下統計出每個點左面和右面的AA串數目即可。
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
char s[50000];
int hash1[50000];
int hash2[50000];
int base1[50000];
int base2[50000];
int mod1=23333;
int mod2=10007;
int get_hash1(int l,int r)
{
int t=hash1[r]-hash1[l-1]*base1[r-l+1];
t%=mod1;
t+=mod1;
t%=mod1;
return t;
}
int get_hash2(int l,int r)
{
int t=hash2[r]-hash2[l-1]*base2[r-l+1];
t%=mod2;
t+=mod2;
t%=mod2;
return t;
}
int v[50000];
int u[50000];
int main()
{
//freopen("excellent.in","r",stdin);
//freopen("excellent.out","w",stdout);
int T;
scanf("%d",&T);
base1[0]=1;
base2[0]=1;
for(int i=1;i<=30000;i++) base1[i]=base1[i-1]*233%mod1;
for(int i=1;i<=30000;i++) base2[i]=base2[i-1]*2333%mod2;
while(T--)
{
memset(v,0,sizeof(v));
memset(u,0,sizeof(u));
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;i++)
{
hash1[i]=(hash1[i-1]*base1[1]+s[i])%mod1;
hash2[i]=(hash2[i-1]*base2[1]+s[i])%mod2;
}
for(int L=1;L*2<=len;L++)
{
for(int i=L;i+L<=len;i+=L)
{
int j=i+L;
int l=1,r=L;
int jilu=0;
while(l<=r)
{
int mid=l+r>>1;
if(get_hash1(i-mid+1,i)==get_hash1(j-mid+1,j) && get_hash2(i-mid+1,i)==get_hash2(j-mid+1,j)) jilu=mid,l=mid+1;
else r=mid-1;
}
int LL=jilu;
jilu=0;
l=1,r=min(L,len-j+1);
while(l<=r)
{
int mid=l+r>>1;
if(get_hash1(i,i+mid-1)==get_hash1(j,j+mid-1) && get_hash2(i,i+mid-1)==get_hash2(j,j+mid-1)) jilu=mid,l=mid+1;
else r=mid-1;
}
int RR=jilu;
l=i-LL;
r=i+RR-L-1;
if(l<=r)
{
v[l]+=1;
v[r+1]-=1;
}
r=j+RR-1;
l=j-LL+L;
if(l<=r)
{
u[l]+=1;
u[r+1]-=1;
}
}
}
long long ans=0;
for(int i=0;i<=len;i++)
{
if(i!=0) u[i]+=u[i-1],v[i]+=v[i-1];
ans+=1ll*u[i]*v[i];
}
cout<<ans<<endl;
}
//fclose(stdin);
//fclose(stdout);
return 0;
}