題目描述
小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整除。
必然被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個數字有個數字是不可以被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等數整除的數的特徵