【數位dp入門】51nod 1009 數字1的數量
阿新 • • 發佈:2019-01-24
給定一個十進位制正整數N,寫下從1開始,到N的所有正數,計算出其中出現所有1的個數。
N(1 <= N <= 10^9)
dp[i] 表示 0 ~ (10 ^ i - 1) 中1的個數。
ten[i] 表示 10 ^ i 的值
pos 當前處理的位
num 當前處理的位前面已經有的1個數
limit 當前位有沒限制
其實dp可以看作記錄過程答案的dfs。(即是記憶化搜尋) 可以把這題當作dfs做。
對於 0 ~ 4321 有多少個1呢?
圖:
修正:雖然這題過掉了,後來做 hdu 2098 ,根據我自己的理解碼程式碼,無限wa,不知道是錯在哪裡,後來強行手跑程式碼,發現先前的理解不準確。
進一步理解:數位dp的記憶化搜尋不能理解為邊爆搜邊記錄,這樣是沒有意義的(之前腦子懵),如上圖:它先在最深一層搜10次(0000~0009),記錄dp值,運用在最後第二層搜10次(001X~009X)上,以此類推,搞出所有需要的dp值無非只搜了 (位數*10)次;
#include<iostream> #include<cstdio> #include<cstring> #include<stack> #include<map> #include<queue> #include<cmath> #include<algorithm> #include<deque> typedef long long LL; using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") const int INF=0x3f3f3f3f; const int N = 20; const double eps = 1e-6; int ten[N]; //10^i 的值 void init() { ten[0] = 1; for(int i = 1; i < 10; i++) ten[i] = ten[i-1]*10; } char s[N]; int len; int dp[N]; //0->10^i-1 中1的個數 int dfs(int pos,int num, int limit) { if(pos == len) return num; if(!limit && dp[len-pos-1] != -1) return num*ten[len-pos]+dp[len-pos-1]; int up = limit ? s[pos]-'0' : 9; int tmp = 0; for(int i = 0; i <= up; i++) tmp += dfs(pos+1,num+(i==1),limit && s[pos]-'0' == i); if(!limit) dp[len-pos-1] = tmp; return tmp; } int main() { init(); scanf("%s",s); len = strlen(s); memset(dp,-1,sizeof(dp)); printf("%d\n",dfs(0,0,1)); return 0; }