临洮巨人

来源:互联网 发布:青岛知豆电动车租赁500 编辑:程序博客网 时间:2024/04/28 10:41

题目描述:

引用块内容

输入:

一行一个由大写字母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]时这个区间就是合法的。
时间复杂度o(n2),只能拿到70分。

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*104+y。显然,每一个相等的z都可以组成一个合法的答案。
这个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);}
1 0