题目:
题解:
95分的hash(为什么暴力分这么良心啊)
显然我们不需要找AABB的形式,只需要找到AA的形式就好了
l[i]表示i位及前面的有多少AA的形式,r[i]表示i+1位及以后有多少AA的形式
那么答案就是
∑l[i]r[i]
∑
l
[
i
]
r
[
i
]
95就行了我hin满意了
感觉也是后缀家族的一员吧,讲解的话这个blog讲的特别好啊,后缀数组+RMQ也很常见,当个板子练练吧
最后用了一个差分,因为是区间加操作,用差分比较好,时间复杂度为O(n/1+n/2+…+n/n)=O(nlogn)
代码:
95的hash
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
const int base=131;
const int mod=998244353;
const int N=2005;
LL mul[N],hash[N];char st[N];
int main()
{
int T;scanf("%d",&T);
mul[0]=1;
for (int i=1;i<=2000;i++) mul[i]=mul[i-1]*base%mod;
while (T--)
{
scanf("%s",st+1);int n=strlen(st+1);
for (int i=1;i<=n;i++)
hash[i]=(hash[i-1]*base+st[i])%mod;
int ans=0;
for (int i=1;i<=n;i++)
{
int l=0,r=0;
for (int j=1;j<=n;j++)
{
if (i-j*2>=0)
if ((hash[i]-hash[i-j]*mul[j]%mod+mod)%mod==(hash[i-j]-hash[i-j*2]*mul[j]%mod+mod)%mod) l++;
if (i+j*2<=n)
if ((hash[i+j]-hash[i]*mul[j]%mod+mod)%mod==(hash[i+2*j]-hash[i+j]*mul[j]%mod+mod)%mod) r++;
}
ans+=l*r;
}
printf("%d\n",ans);
}
}
100
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
const int N=60005;
int n;LL l[N],r[N];char st[N];
struct hzsz
{
int sa[N],x[N],y[N],f[N][25],rak[N],height[N],c[N];
char s[N];
void build_sa()
{
int m=300;
for (int i=0;i<m;i++) c[i]=0;
for (int i=0;i<n;i++) c[x[i]=s[i]]++;
for (int i=1;i<m;i++) c[i]+=c[i-1];
for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for (int k=1;k<=n;k<<=1)
{
int p=0;
for (int i=n-k;i<n;i++) y[p++]=i;
for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;
for (int i=0;i<m;i++) c[i]=0;
for (int i=0;i<n;i++) c[x[y[i]]]++;
for (int i=1;i<m;i++) c[i]+=c[i-1];
for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y); p=1; x[sa[0]]=0;
for (int i=1;i<n;i++) x[sa[i]]= y[sa[i]]==y[sa[i-1]]
&& ((sa[i]+k>=n?-1:y[sa[i]+k])==(sa[i-1]+k>=n?-1:y[sa[i-1]+k]))?p-1:p++;
if (p>n) break;
m=p;
}
}
void build_height()
{
for (int i=0;i<n;i++) rak[sa[i]]=i;
height[0]=0;int k=0;
for (int i=0;i<n;i++)
{
if (!rak[i]) continue;
if (k) k--;
int j=sa[rak[i]-1];
while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
height[rak[i]]=k;
}
}
void init()
{
memset(sa,0,sizeof(sa));
memset(f,0,sizeof(f));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(height,0,sizeof(height));
memset(rak,0,sizeof(rak));
build_sa();build_height();
for (int i=0;i<n;i++) f[i][0]=height[i];
for (int i=1;i<20;i++)
for (int j=0;j<n;j++)
if (j+(1<<i)-1<n) f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
else break;
}
int lcp(int a,int b)
{
int l=rak[a],r=rak[b];
if (r<l) swap(l,r);
if (r<0) return 0;l++;
int k=log2(r-l+1);
return min(f[l][k],f[r-(1<<k)+1][k]);
}
}s1,s2;
int main()
{
int T;scanf("%d",&T);
while (T--)
{
memset(l,0,sizeof(l));memset(r,0,sizeof(r));
scanf("%s",st);n=strlen(st);
for (int i=0;i<n;i++) s1.s[i]=st[i],s2.s[i]=st[n-i-1];
s1.init(); s2.init();
for (int i=1;i<=n/2;i++)
{
int last=0;
for (int j=1;j+i<=n;j+=i)
{
int x=s1.lcp(j-1,j+i-1),y=s2.lcp(n-j-i,n-j);
int ll=max(j,j+i-y),rr=min(j+i,j+x)-1;
if (ll<=rr)
{
l[ll+i]++; l[rr+i+1]--;
r[ll-i]++; r[rr-i+1]--;
}
}
}
LL ans=0;
for (int i=1;i<=n;i++) l[i]+=l[i-1],r[i]+=r[i-1];
for (int i=1;i<=n;i++) ans+=l[i]*r[i];
printf("%lld\n",ans);
}
}