什么数可以被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整除。


回到题目中去,现在只要把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整除的位置是有规律的:

数字 1 12 123 1234 12345 123456 1234567 12345678 123456789
余数 1 0 0 1 0 0 1 0 0

可以发现:每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等数整除的数的特征

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章