ACM 不要62 (數字DP)

2021-09-07 01:43:09 字數 4515 閱讀 4654

題目:

杭州人稱那些傻乎乎粘嗒嗒的人為62(音:laoer)。

杭州交通管理局經常會擴充一些的士車牌照,新近出來乙個好訊息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大眾。

不吉利的數字為所有含有4或62的號碼。例如:

62315 73418 88914

都屬於不吉利號碼。但是,61152雖然含有6和2,但不是62連號,所以不屬於不吉利數字之列。

你的任務是,對於每次給出的乙個牌照區間號,推斷出交管局今次又要實際上給多少輛新的士車上牌照了。

思路:寫了乙個蠻力演算法,直接超時了。之後各種想不出來,上網搜答案。結果發現有專門的解法,叫數字dp。之後看答案看了2個小時,那50行**翻來覆去看了好久,終於看明白了。

唉,大神們寫**的時候注釋都太精簡了,像我這種沒學過數字dp的看得很痛苦啊。

下面解析一下:

題目會給出兩個數字 m 和 n,我們要找到 【m, n】區間內,不含4與62的數字的個數。

①我們把問題拆解為兩個部分, 分別求0 ~ m - 1 和 0 ~ n 之間的不含4與62的數字的個數,然後相減。

②但是0~n中的不含4與62的值求解也很複雜,所以我們先進一步化簡,求0到 i 位數的不含4和62的數字個數。

比如:

i = 1,即求 0 ~ 9 中不含4和62的數字個數

i = 2,即求 0 ~ 99 中不含4和62的數字的個數

i = 3,即求 0 ~ 999 中不含4和62的數字個數

i = 4,即求 0 ~ 9999 中不含4和62的數字的個數

..... 以此類推

用dp[i][0] 來儲存 0 到 i 位數字中不含4和62的數字個數,即幸運數

用dp[i][1] 來儲存 0 到 i 位數字中以 2 開頭的幸運數。

用dp[i][2] 來儲存 0 到 i 位數字中的非幸運數,即包含4或者62的數字。

那麼,可以用下面的遞推公式

dp[i][0] = dp[i - 1][0] * 9 - dp[i - 1][1]   // i 位數字中的幸運數個數 = (i - 1)位幸運數字前面加上0 - 9 中除去4以外的9個數字 - 以2開頭的(i - 1)位幸運數字前面加上了6.

dp[i][1] = dp[i - 1][0]   // 0到 i 位數字中以2開頭的幸運數 = 0到 i 位數字中所有的幸運數字前面加上2

dp[i][2] = dp[i - 1][2] * 10 + dp[i - 1][0] + dp[i - 1][1]  //0到 i 位的非吉利數 = 0到 i - 1 位的非吉利數前面加上0-9的任何數字 + i-1位的吉利數字前面加上了4 + i-1位以2開頭的吉利數字前面加上了6.

初始值:  dp[0][0] = 1  dp[0][1] = dp[0][2] = 0;

根據初始值和遞推公式,我們就能得到從0到任意i位數字的吉利數字的個數。

③找到0 ~ n 的吉利數字的個數

我們先求出0 ~ n 之間非吉利數字的個數,用總數減去即可。那,非吉利數字的個數怎麼求呢? 

用具體的數字舉例來說吧:設 n = 583626

用digit[10]記錄n+1每一位對應的數字,此例中有6位數字(令cnt = 6 表示數字位數),分別是

digit[6] = 5  

digit[5] = 8 

digit[4] = 3

digit[3] = 6

digit[2] = 2

digit[1] = 7

digit[0] = 任意數字,佔位用的

用sum記錄非吉利數字的個數,初始化為0

需要乙個bool量 flag,記錄是否出現了非吉利數字。初始化為false, 未出現。

我們從數字的最高位起進行判斷:digit[6] = 5, 我們求 0 ~ 499999 之間非吉利數的個數。

首先:加上0 ~ 99999中所有非吉利數字前面新增0~4的任意乙個數字的情況   sum += dp[5][2] * digit[6]

其次:5大於4,故我們要加上 0~99999中所有吉利數字前面新增4的情況       sum += dp[5][0]

接著,判斷第5位digit[5] = 8,即判斷500000 ~ 579999 之間的非吉利數字的個數,其實就是判斷0 ~ 79999之間的,前面的數字不是6就沒有什麼用

首先:加上0 ~ 9999中所有非吉利數字前面新增0~7的任意乙個數字的情況 sum += dp[4][2] * digit[5]

其次:8大於4,故我們要加上 0~9999中所有吉利數字前面新增4的情況       sum += dp[4][0]

此外:8大於6,故我們要加上0~9999中所有以2開頭的吉利數字前新增6的情況  sum += dp[4][1]

接著,判斷第4位digit[4] = 3,即判斷580000 ~ 582999 之間的非吉利數字的個數,其實就是判斷0 ~ 2999之間的

首先:加上0 ~ 999中所有非吉利數字前面新增0~2的任意乙個數字的情況 sum += dp[3][2] * digit[4]

其次:2小於4,沒有需要特別考慮的

此外:2小於6,沒有需要特別考慮的

接著,判斷第3位digit[3] = 6,即判斷583000 ~ 583599 之間的非吉利數字的個數,其實就是判斷0 ~ 599之間的

首先:加上0 ~ 99中所有非吉利數字前面新增0~5的任意乙個數字的情況 sum += dp[2][2] * digit[3]

其次:6大於4,故我們要加上 0~99中所有吉利數字前面新增4的情況       sum += dp[2][0]

接著,判斷第2位digit[2] = 2,即判斷583600 ~ 583619 之間的非吉利數字的個數,其實就是判斷0 ~ 19之間的,

首先:加上0 ~ 9中所有非吉利數字前面新增0~1的任意乙個數字的情況 sum += dp[1][2] * digit[2]

其次:2小於4,沒有需要特別考慮的

此外:2小於6,沒有需要特別考慮的

但是,需要注意的是,這裡判斷的數字出現了62,我們要把flag標識為true。

最後,判斷第1位digit[1] = 7, 判斷583620 ~ 583626但是這裡flag為true了,表示前面的數字裡面已經包含了非吉利數字,所以後面需要把所有的數字情況都加入到非吉利裡面。(正是因為每次判斷的數字末尾都比該位的數字少1,所以最開始要記錄n + 1 的值)

sum += digit[1] * dp[0][2] + digit[1] * dp[0][0]

總結一下,這部分的演算法如下:

int flag=0,ans=0

;

for(int i=cnt;i>0;i--)

if(digit[i]==4 || (digit[i+1]==6 && digit[i]==2

)) flag=1

; }

整體的**如下:

#include#include

#include

using

namespace

std;

int dp[10][3

];void init()

}int solve(int

x) digit[cnt+1]=0

;

int flag=0,ans=0

;

for(int i=cnt;i>0;i--)

if(digit[i]==4 || (digit[i+1]==6 && digit[i]==2

)) flag=1

; }

return x-ans; //

所有的數減去非吉利的數

}int

main()

return0;

}

網上有更簡潔的**,用dfs和狀態轉移做的,我沒看懂。

#include #include 

#include

using

namespace

std;

int dp[8][2],digit[8

];int dfs(int len,bool state,bool

fp)

if(!fp)

dp[len][state] =ret;

return

ret;

}int f(int

n)

return dfs(len,false,true);}

intmain()

return0;

}

第三種可以通過的方法是暴力打表,這個比較簡單

#include #include 

int flag[1000001

];int

main()

temp/=10

; }

}while(1

)

printf(

"%d\n

",m-n+1-amount);

}return0;

}

DP 數字 DP 不要62

水一篇題解。掌握了數字 dp 的套路之後,10分鐘就可敲出這道題目。題目 不要62 做法 動態規劃 狀態表示 f i j f i j f i j 表示 i ii 位數,最高位是 j jj 的合法數字個數。預處理 只要不含4並且相鄰兩位不是6 2即可累加 狀態轉移步驟 1 不選最大可填數時 累加 2 ...

不要62(數字DP)

description 杭州人稱那些傻乎乎粘嗒嗒的人為62 音 laoer 杭州交通管理局經常會擴充一些的士車牌照,新近出來乙個好訊息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大眾。不吉利的數字為所有含有4或62的號碼。例如 62315 73...

不要62 (數字dp)

杭州人稱那些傻乎乎粘嗒嗒的人為62 音 laoer 杭州交通管理局經常會擴充一些的士車牌照,新近出來乙個好訊息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大眾。不吉利的數字為所有含有4或62的號碼。例如 62315 73418 88914 都屬...