求0到n之間所有數字中1的個數和

2021-07-28 13:03:18 字數 3428 閱讀 7973

計算4 000 000 000以內的最大的那個f(n)==n的值,函式f的功能是統計0到n之間所有數字中1的個數和。

這道題需要解決2個問題,求數字1的個數和以及求最大的f(n)=n。

一、子問題1:求數字1的個數和

如果n是一位數,可以確定f(n)=1。

如果是二位數,如果 n=13,那麼從 1 到 13 的所有數字:1、2、3、4、5、6、7、8、9、10、11、12、13,個位和十位的數字上都可能有 1,我們可以將它們分開來考慮,個位出現 1 的次數有兩次:1 和 11,十位出現 1 的次數有 4 次:10、11、12 和 13,所以 f(n)=2+4=6。要注意的是 11 這個數字在十位和個位都出現了 1, 但是 11 恰好在個位為 1 和十位為 1 中被計算了兩次,所以不用特殊處理,是對的。再考慮 n=23 的情況,它和 n=13 有點不同,十位出現 1 的次數為 10 次,從 10 到 19,個位出現 1 的次數為 1、11 和 21,所以f(n)=3+10=13。

通過對兩位數進行分析,我們發現,個位數出現 1 的次數不僅和個位數字有關,還和十位數有關:如果 n 的個位數大於等於 1,則個位出現 1 的次數為十位數的數字加 1;如果n 的個位數為 0,則個位出現 1 的次數等於十位數的數字。而十位數上出現 1 的次數不僅和十位數有關,還和個位數有關:如果十位數字等於 1,則十位數上出現 1 的次數為個位數的數字加 1;如

果十位數大於 1,則十位數上出現 1 的次數為 10。

f(13) = 個位出現1的個數 + 十位出現1的個數 = 2 + 4 = 6;

f(23) = 個位出現1的個數 + 十位出現1的個數 = 3 + 10 = 13;

f(33) = 個位出現1的個數 + 十位出現1的個數 = 4 + 10 = 14;

… f(93) = 個位出現1的個數 + 十位出現1的個數 = 10 + 10 =20;

接著分析 3 位數,

如果 n = 123:

個位出現 1 的個數為 13:1, 11, 21, …, 91, 101, 111, 121

十位出現 1 的個數為 20:10~19, 110~119

百位出現 1 的個數為 24:100~123

f(23)= 個位出現 1 的個數 + 十位出現 1 的個數 + 百位出現 1 的次數 = 13 + 20 + 24 = 57;同理我們可以再分析 4 位數、 位數。

根據上面的一些嘗試,下面我們推導出一般情況下,從 n 得到 f(n)的計算方法:

假設 n=abcde,這裡 a、b、c、d、e 分別是十進位制數 n 的各個數字上的數字。如果要計算百位上出現 1 的次數,它將會受到三個因素的影響:百位上的數字,百位以下(低位)的數字,百位(更高位)以上的數字。

(1)如果百位上的數字為 0,則可以知道,百位上可能出現 1 的次數由更高位決定,比如 12 013,則可以知道百位出現 1 的情況可能是 100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共有 1 200 個。也就是由更高位數字(12)決定,並且等於更高

位數字(12)×當前位數(100)。

(2)如果百位上的數字為 1,則可以知道,百位上可能出現 1 的次數不僅受更高位影響,還受低位影響,也就是由更高位和低位共同決定。例如對於 12 113,受更高位影響,百位出現 1 的情況是 100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共 1 200個,和上面第一種情況一樣,等於更高位數字(12)×當前位數(100)。但是它還受低位影響,百位出現 1 的情況是 12 100~12 113,一共114 個,等於低位數字(123)+1。

(3)如果百位上數字大於 1(即為 2~9),則百位上可能出現 1的次數也僅由更高位決定,比如 12 213,則百位出現 1 的可能性為:100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,12 100~12 199,一共有 1 300 個,並且等於更高位數字+1(12+1)

×當前位數(100)。

二、子問題2:求最大的f(n)==n

如果對0~n的所有資料進行列舉驗證f(i)=i,效率會非常低,特別是n非常大的時候,比如本題的4000000000。

所以應該通過恰當的方法快速去除那些不可能的資料,剪枝思想就是尋找過濾條件,提前減少不必要的搜尋路徑。

以下是過濾條件的由來:

(1)當f(n)>n的時候,令c=f(n)-n>0,設b屬於[0,c),即0 <=b < c。因為f(n)是乙個非遞減函式,當n2>n1時,必有f(n2)>=f(n1)。那麼有f(n+b)>=f(n)。又因為b < c且c=f(n)-n,所以b < f(n)-n,得出f(n)>n+b。最後得出f(n+b)>=f(n)>n+b。

也就是說只要b屬於[0,c),當n遞增b的時候,必定有f(n+b)>n+b。因此這些值都可以被剪枝忽略掉。我們取b的上確界值c來說。則有f(n+c)>=f(n)>=n+c。這時才可能出現f(n+c)=n+c的情況。這裡是可能,而不是一定。

所以當f(n)>n的時候,選取遞增步長c=f(n)-n,令n=n+c=n+f(n)-n=f(n)。

(2)當f(n) < n的時候,題目給的上限是4 000 000 000,這是乙個10位數。可以得出結論,當n增加1的時候,f(n)最多增加10。這是一種極端情況,即新增加的那個數是1 111 111 111,所以多了10個1,那麼f(n)最多增加10。目前,選取某個步長b,當n+b時,依然有f(n+b) < n+b,但是依然迅速逼近f(n)==n。

假設現在f(n1) < n1,那麼想要達到f(n1)=n1的情況。f(n1)至少得增加n1-f(n1),而此時,在之前推出的結論基礎上(當n增加1的時候,f(n)最多增加10),可以得出n1最少增加了(n1-f(n1))/10 +1。令n1增加後的結果記為n2=n1+(n1-f(n1))/10 +1。

因此n2 > n1,所以f(n2)>=f(n1),而f(n2)=f < f(n1)+n1-f(n1)=n1。所以n2>n1>f(n2)。

因此,當f(n) < n的時候,取步長為(n-f(n))/10 +1,這樣的話可以迅速逼近f(n)==n。

//

// created by huxijie on 17-3-14.

// 求f(n)=n

#include

using

namespace

std;

//求0到n之間所有數字中1的個數和

unsigned

long fun(unsigned

long n)

ifactor *= 10;

}return icount;

}unsigned

long getmaxfunequaln(unsigned

long upperbound) else

}return max;

}int main()

統計所有0到n之間所有含有數字1的數字和

實現函式int func unsigned n 其中n為正整數,返回從1到n 包含1和n 之間出現的1的個數,如 func 13 6,func 9 1。注意 不能將整數轉化為字串 分析 這個問題可以分解為 對於乙個有digit位的數,可以統計其每個位上出現1的次數,遍歷每個位,累計的次數即為出現1的...

統計1到n之間的所有數字中1出現的個數

實 現函式int func unsigned n 其中n為正整數,返回從1到n 包含1和n 之間出現的1的個數,如 func 13 6,func 9 1。注意 不能將整數轉化為字串 這是網上以為兄弟的分析 分析 對於數n,可以把它分成三段,高位段most,當前位cur,低位段least,每一段分別為...

統計0到n之間1的個數

問題描寫敘述 給定乙個十進位制整數n,求出從1到n的全部整數 現 1 的個數。比如 n 2時 1,2出現了1個 1 n 12時 1,2,3,4,5,6,7,8,9,10,11,12。出現了5個 1 1位數的情況 在解法二中已經分析過,大於等於1的時候。有1個,小於1就沒有。2位數的情況 n 13,個...