临洮巨人

题目描述:

引用块内容

输入:

一行一个由大写字母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);
}

猜你喜欢

转载自blog.csdn.net/kerGH/article/details/53791215