日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU 3555 Bomb (数位DP-记忆化搜索模板)

發布時間:2025/7/25 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU 3555 Bomb (数位DP-记忆化搜索模板) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意

求區間[1,n]內含有相鄰49的數。

思路

比較簡單的按位DP思路。這是第一次學習記憶化搜索式的數位DP,確實比遞推形式的更好理解吶,而且也更通用~可以一般化: 【數位DP模板總結】 int dfs(int pos, int pre, int flag, bool limit) {if (pos == -1) return flag==target_flag;if (!limit && ~dp[pos][pre][flag]) return dp[pos][pre][flag];int res = 0;int end = limit?num[i]:9;for (int d = 0; d <= end; ++d)res += dfs(pos-1, d, (flag, d), limit&&d==end);return limit?res:dp[pos][pre][flag]=res; } 其中:dp為記憶化數組;pos為當前處理串的第pos位;flag為之前數字的狀態(如果要求后面的數滿足什么狀態,也可以再記一個目標狀態target之類,for的時候枚舉下);pre為前一位數字的狀態(有時根據需要也可以加上后一位數字的狀態,for的時候枚舉下);limit表示之前的數是否是上界的前綴(即后面的數能否任意填)。for循環枚舉數字時,要注意是否能枚舉0,以及0對于狀態的影響,有的題目前導0和中間的0是等價的,但有的不是,對于后者可以在dfs時再加一個狀態變量z,表示前面是否全部是前導0,也可以看是否是首位,然后外面統計時候枚舉一下位數。于是關鍵就在怎么設計狀態。當然做多了之后狀態一眼就可以瞄出來。注意:不滿足區間減法性質的話(如hdu 4376),不能用solve(r)-solve(l-1),狀態設計會更加詭異。 這道題思路比較簡單,看看遞推代碼就明白了,然后再看看記憶化搜索代碼就更好理解了~

代碼

? [cpp] //遞推形式 #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <algorithm> #include <string> #include <cstring> #include <set> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, m) for (int i = begin; i < begin+m; i ++) using namespace std; const int maxn = 35; typedef long long LL; LL dp[maxn][3]; //dp[i][0]表示長度為i,包括49的個數 //dp[i][1]表示長度為i,沒有49但是開頭為9的個數 //dp[i][2]表示長度為i,沒有49 void init(){ MEM(dp, 0); dp[0][2] = 1; REP(i, 1, 22){ dp[i][0] = (LL)dp[i-1][0]*10 + dp[i-1][1]; dp[i][1] = (LL)dp[i-1][2]; dp[i][2] = (LL)dp[i-1][2]*10 - dp[i-1][1]; } } LL solve(LL n){ vector <int> bit; while(n){ bit.push_back(n%10); n /= 10; } LL ans = 0; bool flag = false; bit.push_back(0); for (int i = bit.size() - 1; i >= 1; i --){ ans += (LL)dp[i-1][0]*bit[i-1]; if (!flag && bit[i-1] > 4){ ans += (LL)dp[i-1][1]; } if (flag){ ans += (LL)dp[i-1][2]*bit[i-1]; } if (bit[i-1] == 9 && bit[i] == 4){ flag = true; } } if (flag) ans ++; return ans; } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int t; scanf("%d", &t); init(); while(t --){ LL n; scanf("%I64d", &n); printf("%I64d\n", solve(n)); } return 0; } [/cpp] [cpp] //記憶化搜索形式 #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, m) for (int i = begin; i < begin+m; i ++) using namespace std; typedef long long LL; typedef vector <int> VI; typedef set <int> SETI; typedef queue <int> QI; typedef stack <int> SI; VI dig; LL dp[30][30][2]; LL dfs(int pos, int pre, int flag, int limit){ if (pos == -1) return flag; if (!limit && dp[pos][pre][flag] != -1){ return dp[pos][pre][flag]; } int end = limit?dig[pos]:9; LL ret = 0; for (int i = 0; i <= end; ++ i){ ret += dfs(pos-1, i, (i==9 && pre == 4)||flag, (i == end)&&limit); } if (!limit) dp[pos][pre][flag] = ret; return ret; } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int t; scanf("%d", &t); while(t --){ LL n; scanf("%I64d", &n); dig.clear(); MEM(dp, -1); while(n){ dig.push_back(n%10); n /= 10; } printf("%I64d\n", dfs(dig.size()-1, 0, 0, 1)); } return 0; } [/cpp]

轉載于:https://www.cnblogs.com/AbandonZHANG/p/4114309.html

總結

以上是生活随笔為你收集整理的HDU 3555 Bomb (数位DP-记忆化搜索模板)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。