zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    42     }
    43 
    44     return 0;
    45 }
    View Code(严格的数据会超int的数据范围,故用longlong)
  • 相关阅读:
    Python str转化成数字
    MySQL之CONCAT()的用法
    MySQL之LIMIT用法
    MySQL中LOCATE用法
    设计模式-模版方法
    设计模式-单例模式
    设计模式-桥接模式
    UML图标含义及记忆方法
    redis-分布式锁-消除竞争条件
    redis-分布式锁-刷新信号量
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/9441372.html
Copyright © 2011-2022 走看看