HDU 2089 不要62 数位DP
題目鏈接:?http://acm.hdu.edu.cn/showproblem.php?pid=2089
題目描述: 給定一個區間, 讓你求這個區間中所有不帶62 或 4 的數的個數
解題思路: 很明顯的數位DP, 統計個數, f(i) 表示 0 ~ i 的滿足條件的數的個數, 那么最后答案就是f(r) - f(l)。 給出一個數位DP模板的詳解, 解釋的很詳細很清楚
轉自:http://www.cnblogs.com/xz816111/p/4809913.html
// pos = 當前處理的位置(一般從高位到低位) // pre = 上一個位的數字(更高的那一位) // status = 要達到的狀態,如果為1則可以認為找到了答案,到時候用來返回, // 給計數器+1。 // limit = 是否受限,也即當前處理這位能否隨便取值。如567,當前處理6這位, // 如果前面取的是4,則當前這位可以取0-9。如果前面取的5,那么當前 // 這位就不能隨便取,不然會超出這個數的范圍,所以如果前面取5的 // 話此時的limit=1,也就是說當前只可以取0-6。 // // 用DP數組保存這三個狀態是因為往后轉移的時候會遇到很多重復的情況。 int dfs(int pos,int pre,int status,int limit) {//已結搜到盡頭,返回"是否找到了答案"這個狀態。if(pos < 1)return status;//DP里保存的是完整的,也即不受限的答案,所以如果滿足的話,可以直接返回。if(!limit && DP[pos][pre][status] != -1)return DP[pos][pre][status];int end = limit ? DIG[pos] : 9;int ret = 0;//往下搜的狀態表示的很巧妙,status用||是因為如果前面找到了答案那么后面//還有沒有答案都無所謂了。而limti用&&是因為只有前面受限、當前受限才能//推出下一步也受限,比如567,如果是46X的情況,雖然6已經到盡頭,但是后面的//個位仍然可以隨便取,因為百位沒受限,所以如果個位要受限,那么前面必須是56。////這里用"不要49"一題來做例子。for(int i = 0;i <= end;i ++)ret += dfs(pos - 1,i,status || (pre == 4 && i == 9),limit && (i == end));//DP里保存完整的、取到盡頭的數據if(!limit)DP[pos][pre][status] = ret;return ret; } 數位DP模板詳解然后再來說這道題, 我們dfs函數用三個參數來表示已知, 一個是進行到第幾位這是肯定的, 還有一個是上一位是不是為6, 因為如果上一位為6, 那么當前為就不能為2, 還有一個參數就是limit, 用來限制不超過數i的.....
dfs(int len, int isSix, int limit); 數位DP都是從高位到低位, 因為這樣可以發揮limit(枚舉前一位是否等于處理的i的前一位)的作用,如果說枚舉的前一位小于i的前一位, 那么下一位就隨便取(0 ~ 9), 但是如果等于的話, 就只能取0 ~ digit[len]的數, 到了digit[len]還會面臨相同的問題, 以此類推......吃完飯來寫一下這道題.......吃完啦, 開始學習
代碼:?
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <map> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <map>#define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 typedef long long LL; using namespace std; const int maxn = 70000+10; int digit[8]; int dp[8][2];int dfs( int len, int isSix, int limit ) {if( !len ) return 1;if( !limit && dp[len][isSix] != -1 ) {return dp[len][isSix];}int ret = 0;int tlimit = limit ? digit[len] : 9;for( int i = 0; i <= tlimit; i++ ) {if( i == 4 ) continue;if( isSix && i == 2 ) continue;ret += dfs( len-1, i == 6, limit && i == tlimit );}if( !limit ) dp[len][isSix] = ret;return ret; } int fun( int n ) {int cnt = 0;while( n ) {digit[++cnt] = n % 10;n /= 10;}return dfs( cnt, 0, 1 ); }int main() {int l, r;while( scanf("%d%d", &l, &r) != EOF ) {if( l == 0 && r == 0 ) break;memset(dp, -1, sizeof(dp));printf( "%d\n", fun(r) - fun(l-1) );}return 0; } View Code思考: 以前仔細看過數位DP的代碼, 但是今天講課的時候發現又忘了, 剛才又寫了一遍, 挺順的, 以后多多多多復習吧
?
轉載于:https://www.cnblogs.com/FriskyPuppy/p/7324744.html
總結
以上是生活随笔為你收集整理的HDU 2089 不要62 数位DP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017 Material design
- 下一篇: “云+大数据”时代 中端存储如何选择