题解:
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); } }