ZZNU-oj-2141:2333--【O(N)求一个数字串能整除3的连续子串的个数,前缀和数组+对3取余组合数找规律】...

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;

 

面向样例编出来的代码:

 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\n",ans);
42     }
43 
44     return 0;
45 }
View Code(严格的数据会超int的数据范围,故用longlong)

 

转载于:https://www.cnblogs.com/zhazhaacmer/p/9441372.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值