题目描述:
输入:
一行一个由大写字母A到L组成的字符串S。
ABACABA
输出:
2
样例解释:BAC和CAB
数据范围:
对于30%的数据,|S|<=100。
对于70%的数据,|S|<=1000。
对于100%的数据,1<=|S|<=1000000。
分析:
70%:
用a[i],b[i],c[i]分别表示在第i个位置,a、b、c分别出现了多少次。
枚举一个区间i,j,那么,当a[i]-a[j]=b[i]-b[j]=c[i]-c[j]时这个区间就是合法的。
时间复杂度
100%:
我们知道a[i]-a[j]=b[i]-b[j]=c[i]-c[j],化简得
a[i]-b[i]=a[j]-b[j]
b[i]-c[i]=b[j]-c[j]
设x=a[i]-b[i],y=b[i]-c[i],z=x*
这个z会很大,我们用hash去维护。
z也可能是负数,hash时在mod之前要对z取绝对值。
CODE:
#include<cstdio>
#include<cstring>
#include<algorithm>
const long long add=10000;
const long long mo=10000007;
long long n,f[4][1000001],a[1000001],h[2][10000007],x1,x2,x3;
long long get(long long x,long long y)
{
long long i=abs(x+y)%mo;
while (h[0][i]!=-9114861777597660799 && h[0][i]!=x+y)
{
i++;
}
return i;
}
int main()
{
long long i,j,k;
char c;
scanf("%c",&c);
while (c>='A' && c<='Z')
{
n++;
a[n]=c-'A'+1;
scanf("%c",&c);
}
long long ans=0;
long long x=0,y=0;
long long z;
memset(h[0],-0x7f,sizeof(h[0]));
for (i=0;i<=n;i++)
{
if (i==200000)
{
printf("");
}
if (a[i]==1) x1++;
else if (a[i]==2) x2++;
else if (a[i]==3) x3++;
x=x1-x2;
y=x2-x3;
z=get(x*add,y);
ans+=h[1][z];
h[0][z]=x*add+y;
h[1][z]++;
}
printf("%lld",ans);
}