2141: 2333
题目描述 “别人总说我瓜,其实我一点也不瓜,大多数时候我都机智的一批“ 宝儿姐考察你一道很简单的题目。给你一个数字串,你能判断有多少个连续子串能整除3吗? 输入 多实例输入,以EOF结尾,每行一个数字串(长度<=1e6) 输出 每行一个数字串,表示能整除3的连续子串的个数 样例输入 2333 121 14533254 (随机敲了一组样例,发现了新的bug) 样例输出 6 2 10
大致思路:
根据题意可知,时间复杂度只够跑单重循环,多重循环就炸了!
求一次前缀和,存进dp数组!然后对3取余,分别求出0/1/2的个数为sum0和sum1和sum2;
由面向(第三组)样例编程原理可知,其前缀和数组%3取余后的结果dp=“ 121 110 20 ”,sum0=2,sum1为4,sum2为2;
每个前缀和%3为0,最终结果ans+=sum0,然后每两个o对应的下标i和j之间那段的和也是0(因为0-0=0),故ans+=(sum*(sum-1)/2);
然后每两个1对应的下标i和j之间那段的和也是1(因为1-1=0),故ans+=(sum1*(sum1-1)/2);——这个式子也就是组合式:C(n=sum1,m=2);
然后每两个2对应的下标i和j之间那段的和也是0(因为2-2=0),故ans+=(sum2*(sum2-1)/2);
数学推理:
求出前缀和数组为sum,sumi-sumj表示i--j的数组和;
若(sumi-sumj)%3==0, 推得sumi%3 -sumj%3==0; 枚举可知sumi和sumj同为0,1,2即可!
遍历一遍对3取余后的sum数组即可得到0,1,2的个数为sum0和sum1和sum2!
ans=sum0*(sum0-1)/2+sum1*(sum1-1)/2+sum2*(sum2-1)/2+sum0;
面向样例编出来的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<string> 5 #include<algorithm> 6 #include<vector> 7 #include<queue> 8 #include<math.h> 9 #include<map> 10 #include<set> 11 #define ll long long 12 using namespace std; 13 #define N 1000008 14 #define lson rt<<1 15 #define rson rt<<1|1 16 17 char s[N]; 18 int a[N]; 19 ll dp[N]; 20 int main(){ 21 s[0]='0'; 22 while(scanf("%s",s+1)!=EOF){ 23 int len=strlen(s); 24 memset(dp,0,sizeof(dp)); 25 26 for(int i=1;i<len;i++){ 27 a[i]=s[i]-'0'; 28 dp[i]=(a[i]+dp[i-1])%3; 29 } 30 ll sum0=0,sum1=0,sum2=0,ans=0; 31 for(int i=1;i<len;i++){ 32 if(dp[i]==0) 33 sum0++; 34 else if(dp[i]==1) 35 sum1++; 36 else 37 sum2++; 38 } 39 ans=sum0*(sum0-1)/2+sum1*(sum1-1)/2+sum2*(sum2-1)/2+sum0; 40 41 printf("%lld ",ans); 42 } 43 44 return 0; 45 }