什麼數可以被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等數整除的數的特徵

 

 

 

 

 

 

 

 

 

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