洛谷P2657 [SCOI2009] windy 數
阿新 • • 發佈:2021-08-05
洛谷1587: 【例 3】Windy 數
數位dp裸題
這道題對於前導0加個特判就好
如果前面是前導0,那麼搜尋時把pre賦值成-2(當然<-2的數都可以)
注意:這樣處理之後dp陣列就不能定義為dp[pos][pre][flag][lim](不懂的話見程式碼註釋)。
因為pre哪裡可能會是負數,所以只能有前兩維,記憶化賦值的時候加特判,判斷前面不是前導0,再賦值
不多說了,直接看程式碼吧(有註釋)
#include <iostream> #include <cstdio> #include <cstring> #define ll long long using namespace std; ll l, r, len; ll num[20], dp[15][15]; //dp[pos][pre]:處理到第i位,上一位為j,且當前位可以取0~9,不是全部都為0時的方案數 //注意:這裡不能dp[pos][pre][flag][lim](原因見下) ll dfs(ll pos, ll pre, ll flag, ll lim){ //pos:處理到第幾位,pre:上一位是多少,flag:前面是否為前導0,lim:是否有上限 if(pos == len + 1) return 1; if(!lim && dp[pos][pre] != -1) return dp[pos][pre]; //記憶化,這裡只記憶了沒有上限情況下的方案數 ll res = lim ? num[len - pos + 1] : 9; //找上限,注意這裡是倒著存的數,所以num[len-pos+1] ll ans = 0; for(ll i = 0; i <= res; i++){ if(abs(i - pre) < 2) continue; //相差<2則continue if(flag && !i) ans += dfs(pos + 1, -2, 1, lim && (i == res)); //如果前面為前導0,pre賦值成-2 else ans += dfs(pos + 1, i, 0, lim && (i == res)); //不是前導0的話正常dfs } if(!flag && !lim) dp[pos][pre] = ans; //特判,前面不是前導0,且沒有上限,記憶化 return ans; } ll solve(ll x){ len = 0; while(x){ num[++len] = x % 10; x /= 10; } memset(dp, -1, sizeof(dp)); return dfs(1, -2, 1, 1); } signed main(){ scanf("%lld%lld", &l, &r); printf("%lld\n", solve(r) - solve(l - 1)); return 0; }
完結撒花~