HDU2089 不要62 數字DP

2022-05-31 04:06:10 字數 2187 閱讀 3121

型別:數字dp

傳送門:>here

<

題意:問區間$[n,m]$的數字中,不含4以及62的數字總數

解題思路

數字dp入門題

先考慮一般的暴力做法,整個區間掃一遍,判斷每個數是否合法並累計答案。而數字dp則認為可以換一種方法來列舉,找到對於乙個數的上限,然後在這個限度內列舉每乙個數字來統計答案

為了方便數字dp,題意可以轉化求區間$[0, k]$的符合要求的數字總數,因此答案就是$ans(m)-ans(n-1)$

首先我們可以預處理出dp陣列:$dp[i][j]$表示以$j$開頭的$i$位數的符合要求的數字總數;例如,$dp[2][3]$表示以3開頭的2位數中符合要求的,也就是區間$[30, 39]$中符合要求的。$$dp[i][j] = \sum\limits_dp[i-1][k]$$這個方程很好理解,相當於列舉乙個數字塞到前面,同時需要保證不能把6塞當2前面,並且特判一下4就好了

至於統計答案,我們從上限的最高位開始往下掃瞄。這裡有個很巧妙的思想——每次處理不超過當前這一位的部分。形象地說,對於數字$21358$,最高位掃瞄$0~1$,也就是把答案累積上$dp[5][0~1]$。這一步相當於處理了區間$[0, 19999]$中的所有;此時預設最高位是2,掃瞄到下一位,累積$dp[4][0~0]$,也就相當於處理了區間$[20000,20999]$;依次類推,然後將會處理$[21000,21299]$,$[21300,21349]$,$[21350,21357]$。因此我們可以在$o(lg n * 10)$的複雜度內處理區間$[0, n-1]$。(注意不包括n)$$ans = \sum\limits_^\sum\limits_^dp[i][j]$$

然後在來看判斷62和4的問題:每當我們進入到下一位,我們就將預設上一位確定。此時若確定的那一位為4,那麼之後的都不用考慮了(一定不合法)。同理,如果當前確定的為2且上一位確定的為6,那麼也可以跳出。事實上,這個跳出不是優化,而是必須那麼做——如果不跳出,就會錯誤地累積很多答案。同時,不僅進入下一位的時候要判斷,掃瞄的時候也要判斷。道理一樣

拓展:如果題目要求的不是【不要62】而是【要62】呢?就好像[hdu3555] bomb所要求的一樣,只需要求出所有的【不要62】數字,用n減一下就好了

code

特別需要注意的是$digit[num+1]==0$這一步的處理,如果不加這一步,那麼如果在處理前乙個數字時殘留下了$digit[num+1]==6$,那麼你的程式將不能在最高位填充2了!

另外還有dp陣列的初始化問題:一種是$dp[0][0]=1$,或者對於所有$i \neq 4$,$dp[1][i]=1$。其實這兩者是等效的,因為在統計$dp[1][i]$時,只會累積到$dp[0][0]$為1

/*

by dennyqi 2018.8.13

*/#include

#include

#include

#include

#define r read()

#define max(a,b) (((a)>(b)) ? (a) : (b))

#define min(a,b) (((a)<(b)) ? (a) : (b))

using

namespace

std;

typedef

long

long

ll;const

int maxn = 10010

;const

int maxm = 27010

;const

int inf = 1061109567

;inline

intread()

intn,m,num,x,y;

int dp[10][11],digit[10

];inline

void

init()}}

}inline

int cul(int

x) digit[num+1] = -1

;

for(int i = num; i >= 1; --i)

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

; }

return

res;

}int

main()

return0;

}

HDU2089 不要62 數字DP

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

Hdu2089 不要62 數字dp

include includeint dp 10 3 dp i 0 為位數小於等於i且不含62也不含4的數字的個數 dp i 1 為位數為i且首位為2且不含62也不含4的數字的個數 dp i 2 為位數小於等於i且含62或4的數字的個數 int digit 10 void er int wei in...

hdu 2089 不要62 (數字dp)

思路 用變數記錄吉利數,和最高位為2的吉利數還有不是吉利數的個數。code include include includeusing namespace std int dp 10 3 dp i j i表示位數,j表示狀態 dp i 0 表示不存在不吉利數字 dp i 1 表示不存在不吉利數字,且最...