hdu 3555 Bomb(数位dp)
2014-11-01 22:52
274 查看
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <queue> #include <stack> #include <cassert> #include <algorithm> #include <cmath> #include <set> #include <list> #include <map> #include <limits> using namespace std; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i)) #define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i)) #define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i)) #define MAXN 19 /***************BEGINHERE*****************/ LL f[MAXN+1][10]; LL a[MAXN+1]; LL t; LL n; LL Count(LL x) { int cnt = 0; while(x) { a[cnt++] = x%10; x/=10; } LL ret = 0; a[cnt] = -1; UREP(i, cnt-1, 0) { REP(j, 0, a[i]-1) { if (a[i+1] == 4 && j == 9) continue; ret += f[i+1][j]; } if (a[i+1] == 4 && a[i] == 9) break; } return ret; } int main() { freopen("input.in", "r", stdin); cin >> t; REP(i, 1, 9) f[0][i] = 0; f[0][0] = 1; REP(k, 1, 19) REP(i, 0, 9) { f[k][i] = 0; REP(j, 0, 9) if (!(i == 4 && j == 9)) { f[k][i] += f[k-1][j]; } } while (t--) { cin >> n; cout << n-Count(n+1) + 1 << endl; } return 0; }
记忆化搜索:
注意保存状态的时候的维度问题,比如 dp(pos, pre, flag, limit) 的话
下面的代码是错的,比如140,会得到2的结果
原因是,在049的时候保存了状态 (0, 4, 0)
所以在14*的时候发现 (0,4,0) 这个状态已经是1,就直接返回。。
解决方法是,特判 limit=1 的状态 或者 增加维度
LL dp(int pos, int pre, int flag, int limit) { if (pos < 0) return flag; if (f[pos][pre][flag] == -1) { int last = limit ? d[pos] : 9; LL ret = 0; for (int i=0;i<=last;++i) { LL sav = ret; ret += dp(pos-1, i, flag || pre == 4 && i == 9, limit && i == last); if (ret > sav) { cout << "here: "; cout << pos << ' ' << pre << ' ' << flag << ' ' << limit << " now: " << i << endl; } } f[pos][pre][flag] = ret; } else if (f[pos][pre][flag]) {cout << "bug: ";cout << pos << ' ' << pre << ' ' << flag << ' ' << limit << endl;} return f[pos][pre][flag]; }
正确的记忆化解法
LL f[22][10][2], d[22], n, len; LL dp(int pos, int pre, int flag, int limit) { if (pos < 0) return flag; // 特判 limit 的情况,防止重复计数 if (limit || f[pos][pre][flag] == -1) { int last = limit ? d[pos] : 9; LL ret = 0; for (int i=0;i<=last;++i) { LL sav = ret; ret += dp(pos-1, i, flag || pre == 4 && i == 9, limit && i == last); } f[pos][pre][flag] = ret; } return f[pos][pre][flag]; } LL solve() { len = 0; while (n) {d[len++] = n%10;n /= 10;} memset(f, -1, sizeof(f)); return dp(len-1, 0, 0, 1); }
相关文章推荐
- HDU 3555 Bomb (数位DP)
- hdu 3555 - Bomb [数位dp]
- hdu 3555 Bomb(数位DP)
- hdu 3555 Bomb(数位DP,4级)
- HDU 3555 Bomb(数位DP)
- 动态规划晋级——HDU 3555 Bomb【数位DP详解】
- HDU 3555 Bomb (数位DP)
- hdu 3555 Bomb(数位dp)
- HDU 3555 Bomb 数位dp
- HDU 3555 Bomb 数位DP
- HDU --3555--Bomb--数位DP
- hdu 3555 Bomb 数位dp
- 动态规划晋级——HDU 3555 Bomb【数位DP详解】
- 【数位DP】【HDU 3555】Bomb
- HDU-3555 Bomb 数位DP
- HDU 3555 Bomb 基础数位dp
- 动态规划晋级——HDU 3555 Bomb【数位DP详解】
- HDU-3555 Bomb 数位DP
- hdu 3555 Bomb 数位DP
- hdu 3555 Bomb (数位DP)