E Xieldy And His Password 西安电子科技大学第16届程序设计竞赛网络同步赛


题解:

1、对于十进制是3的倍数的数,它的二进制有一个规律:奇数位上的1和偶数位上的1数量之差为3的倍数。

2、把偶数位上的1全部转化为-1,奇数上的1不变,0不变,求出前缀和。

     数组a[i]代表第i位之前的和。

数据 1 1 0 1 0 1 1 0 ——
a[i] 0 1 0 0 -1 -1 -2 -1 -1

3、如果a[hi]-a[lo]是3的倍数(包括正负),也就是说奇数位上的1和偶数位上的1数量之差为3,则这一段lo~hi这一段字符串满足条件。

4、那么对于lo,hi,如果a[lo]%3==a[hi]%3,那么a[hi]-a[lo]肯定是3的倍数。

    如果a[hi]==-1,a[lo]==2,或者a[hi]==-2,a[lo]==1,(lo和hi可互换)也满足情况。也就是说对于任意的a[i]<0可看作a[i]+3。

5、假设前缀和取模的值相同的个数为n,只需任意取其中的两个作为lo和hi就能满足情况,所以一共有Cn2种情况,对于每种取模的情况累加就是答案。


#include <iostream>
#include <stdio.h>
#include <map>
#include <queue>
#include <string.h>
#include <string>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
char s[1000005];
LL a[1000005];
LL cnt[3];
int main(){
    while(scanf("%s",s)!=EOF){
        memset(a,0,sizeof(a));
        memset(cnt,0,sizeof(cnt));
        LL len=strlen(s);
        for(LL i=0;i<len;i++){
            else if(s[i]=='1') a[i+1]=a[i]+1;
            else a[i+1]=a[i];
        }
        for(LL i=0;i<=len;i++){
            if(a[i]%3<0) cnt[a[i]%3+3]++;
            else cnt[a[i]%3]++;
        }
        LL ans=0;
        for(LL i=0;i<3;i++)
            ans+=cnt[i]*(cnt[i]-1)/2;
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/80048924