一类处理字符串相交的好东西。
题目就是要对每个位置求一整个位置为结尾/开头的能写成SS的串的数量。
除了一些麻烦的算法以外(比如在SAM上启发式合并之类的),一个简单的做法是枚举S的长度,不妨设为d,然后将原串每d个字符切开,发现SS这个串至少碰到两个缝隙,因此计算相邻两段的lcp/lcs就可以知道SS的结尾在某一段中合法的区间,然后用差分维护答案即可。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=30010;int A[N],B[N];char s[N];
namespace SAM_space{
const int SIG=26,LOG=20,N=60010;
struct SAM{
int node_cnt,rt,las,val[N],fa[N],ch[N][SIG];vector<int> g[N];
int f[N<<1][LOG],Log[N<<1],pos[N],d[N],fir[N],dfc;
inline int new_node(int v) { int x=++node_cnt;val[x]=v,fa[x]=0;memset(ch[x],0,sizeof(int)*SIG);return x; }
inline int clear() { return node_cnt=0,rt=las=new_node(0); }
inline int extend(int w,int ps)
{
int p=las,np=new_node(val[p]+1);
while(p&&!ch[p][w]) ch[p][w]=np,p=fa[p];
if(!p) fa[np]=rt;
else{
int q=ch[p][w],v=val[p]+1;
if(val[q]==v) fa[np]=q;
else{
int nq=new_node(v);
memcpy(ch[nq],ch[q],sizeof(int)*SIG);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
while(p&&ch[p][w]==q) ch[p][w]=nq,p=fa[p];
}
}
return pos[ps]=las=np,0;
}
inline int Mymin(int x,int y) { return d[x]<d[y]?x:y; }
inline int dfs(int x)
{
f[fir[x]=++dfc][0]=x,d[x]=d[fa[x]]+1;
Rep(i,g[x]) dfs(g[x][i]),f[++dfc][0]=x;return 0;
}
inline int build()
{
int n=node_cnt;rep(i,1,n) vector<int>().swap(g[i]);
rep(i,2,n) g[fa[i]].pb(i);
dfc=0,dfs(1);rep(i,2,dfc) Log[i]=Log[i>>1]+1;
for(int j=1;(1<<j)<=dfc;j++)
for(int i=1;i+(1<<j)-1<=dfc;i++)
f[i][j]=Mymin(f[i][j-1],f[i+(1<<(j-1))][j-1]);
return 0;
}
inline int getLCA(int x,int y)
{
x=fir[x],y=fir[y];if(x>y) swap(x,y);
int k=Log[y-x+1];return Mymin(f[x][k],f[y-(1<<k)+1][k]);
}
inline int query(int x,int y) { return val[getLCA(pos[x],pos[y])]; }
}lcs,lcp;
}using SAM_space::lcs;using SAM_space::lcp;
inline int upd(int *A,int l,int r) { return A[l]++,A[r+1]--; }
inline int solve(int l,int n)
{
for(int i=2;i<=n/l;i++)
{
int x=(i*l+1<=n?lcp.query((i-1)*l+1,i*l+1):0);
int y=lcs.query((i-1)*l,i*l),L=max(l-y,0),R=min(x,l-1);
if(L<=R) upd(A,i*l+L,i*l+R),upd(B,(i-2)*l+1+L,(i-2)*l+1+R);
}
return 0;
}
int main()
{
for(int T=inn();T;T--)
{
scanf("%s",s+1);int n=(int)strlen(s+1);lint ans=0;
lcs.clear(),lcp.clear();
rep(i,1,n) lcs.extend(s[i]-'a',i);
for(int i=n;i;i--) lcp.extend(s[i]-'a',i);
lcs.build(),lcp.build();
memset(A,0,sizeof(int)*(n+1));
memset(B,0,sizeof(int)*(n+1));
rep(len,1,n/2) solve(len,n);
rep(i,1,n) A[i]+=A[i-1],B[i]+=B[i-1];
rep(i,1,n-1) ans+=(lint)A[i]*B[i+1];
printf("%lld\n",ans);
}
return 0;
}