題目16:整數中1出現的次數
時間限制:1 秒
記憶體限制:32 兆
特殊判題:否
-
題目描述:
-
親們!!我們的外國友人YZ這幾天總是睡不好,初中奧數裡有一個題目一直困擾著他,特此他向JOBDU發來求助信,希望親們能幫幫他。問題是:求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。
-
輸入:
-
輸入有多組資料,每組測試資料為一行。
每一行有兩個整數a,b(0<=a,b<=1,000,000,000)。
-
輸出:
-
對應每個測試案例,輸出a和b之間1出現的次數。
-
範例輸入:
-
0 51 1321 5531 99
-
範例輸出:
-
1647
題目分析:找出1到a所有整數中1出現的次數和1到b所有整數中1出現的次數,然後求其差值即可。此題不可用暴力演算法,會逾時,最大範圍為10億。那麼我們來分析一下,看看能不能有其他的求解辦法。
例如1234這個數,1的個數之和為千位上出現的次數+百位上出現的次數+十位上出現的次數+個位上出現的次數,
即1出現的次數689 = 235 + 100 + 130 + 124
又例如1046這個數,1出現的次數362 = 47 + 100 + 110 + 105
再例如1146這個數,1出現的次數362 = 147 + 147 + 120 + 115
通過分析可知,在某位上出現1的次數與自身位相關,而且也與之前的位和之後的位相關。
由此可將一個數拆分為 前面部分+中間位+後面部分,或front+mid+back(例如1146在求百位中的1出現次數時,可看成1+1+46來處理)
我們可得如下規律:
當mid > 1時, 1出現的次數為10^(back的位元) * (front+1) ;
當mid == 1時,1出現的次數為10^(back的位元)* front + (back + 1) ;
當mid == 0時,1出現的次數為10^(back的位元) * front ;
代碼如下:
#include <stdio.h>long long fun(long long n){if(n < 1)return 0;long long count = 10, num = 0, front, mid, back,m;front = n;mid = 0;back = 0;while(front){front = n/count;m = n%count;mid = m/(count/10);back = m%(count/10);if(mid > 1)num = num + (count/10) * (front+1);else if(mid == 1)num = num + (count/10) * front + (back + 1);else num = num + (count/10) * front;count = count * 10;}return num;}int main(){long long n,m;while(scanf("%lld %lld",&n,&m)!=-1)if(n>m)printf("%lld\n",fun(n) - fun(m-1));elseprintf("%lld\n",fun(m) - fun(n-1));return 0;}
注意:a和b的輸入是不分大小的