計算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,個...