什么数可以被3整除——不只是各个位相加被3整除——由一道编程题引发的思考


题目描述

小Q得到一个神奇的数列: 1, 12, 123,...12345678910,1234567891011...。

并且小Q对于能否被3整除这个性质很感兴趣。

小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。

输入描述:

输入包括两个整数l和r(1 <= l <= r <= 1e9), 表示要求解的区间两端。

输出描述:

输出一个整数, 表示区间内能被3整除的数字个数。

题目的意思是,给出一个序列:1,12,123,1234,12345……即第i个数是在第i-1个数的末尾加上i。

一个数能否被3整除,其实在小学就有接触过:各个数位上的数字和能被3整除,那么这个数能被3整除

喵哥在做这道题的时候想过把一个数字的每一位加起来,然后看结果是否可以被3整除。但是,发现这样做很麻烦,而且会超出时间限制。然后,喵哥开始在纸上写写画画,发现一个秘密:

对于一个整数,从其中取出连续的子数,把这些子数相加,如果得到的结果可以被3整除,那么这个数就可以被3整除

例如:

777

77+7=84

证明如下:


假设有一个4位数abcd,其中ab+cd可以被3整除,证明abcd可以被3整除。

ab+cd = 10a+b+10c+d

abcd = 1000a+100b+10c+d = 100(10a+b)+10c+d=99(10a+b)+10a+b+10c+d

99(10a+b)必然被3整除,而ab+cd被3整除是条件,所以abcd可以被3整除。

这个可以推广到n位数,因为提取的字数在原数中是连续的,所以一定可以把原数中较高位的子数写成10^n\times(提取的子数),然后在这个式子中提取出一个子数与后面的子数构成条件中可以被3整除的多项式,剩余的数字一定是(10^n-1)\times(提取的子数),即为99……99×(提取的子数),这是一定可以被3整除的。从而,n位数也可以被3整除。


回到题目中去,现在只要把1到 l 的数相加就可以得到第 l 个数。对于从 l 到 r 的数,每次累加一个对应的数字,然后判断是否可以被3整除即可。

#include <bits/stdc++.h>
using namespace std;

long long getBaseNum(long long end){
    return (1+end)*end/2;
}

int main(){
    long long  l, r;
    cin >> l >> r;
    long long baseNum = getBaseNum(l);
    long long count = 0;
    for(int i = l + 1; i <= r + 1; i++){
        if(baseNum % 3 == 0)
            count++;
        baseNum += i;
    }
    cout << count;
    return 0;
}

其实,这样的解题思路还是不够好,对于很极端的例子,运行时间还是蛮长的。仔细观察会发现,这个序列可以被3整除的位置是有规律的:

数字112123123412345123456123456712345678123456789
余数100100100

可以发现:每3个数中有一个是不可以被3整除的,只要用r - l +1减去不可以整除数字的数量,就可以得到被3整除的数量。

对于i,前i个数字有(i+2)/3个数字是不可以被3整除的。

这样计算就更快了。

#include <bits/stdc++.h>
using namespace std;

int main(){
    int l,r;
    cin >> l >> r;
    cout << (r - l + 1 - ((r + 2) / 3 - (l - 1 + 2) / 3));
    return 0;
}

 

其他的一些数字的整除特征可以参考:能被2、3、4、5、6、7、8、9等数整除的数的特征

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值