HDU - 3555 Bomb (数位dp)
2018-03-11 14:24
295 查看
题目链接:https://cn.vjudge.net/contest/163023#problem/D
题目大意:要求1~n的范围内含有49的数字的个数
题目分析:做的数位dp的第二道题,有三种方法。
第一种(自己想到的):
求出1~n范围内不含49的个数,然后用总数减去不含49的个数再加一(多减了一个0)
代码如下:
第二种方法:
假设n是123456, 当dfs到049_ _ _时,很显然,后三位可放置任意数,共有10 * 10 * 10种放置方法,这种是!limit的情况,当n是49123时,我们跑到49
_ _ _时,后边就只有123 + 1种方法。所以只要标记好limit,预处理出没有限制的情况,就可以轻松算出结果。
第三种方法:
就是传统的数位dp,当时实在是太差了,这都想不出来。。
题目大意:要求1~n的范围内含有49的数字的个数
题目分析:做的数位dp的第二道题,有三种方法。
第一种(自己想到的):
求出1~n范围内不含49的个数,然后用总数减去不含49的个数再加一(多减了一个0)
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int data[30]; ll dp[30][2]; ll dfs(int pos, int pre, bool limit) { if(pos == -1) return 1; if(!limit && dp[pos][pre == 4]) { return dp[pos][pre == 4]; } int up = limit ? data[pos] : 9; ll ans = 0; for(int i = 0; i <= up; i++) { if(i == 9 && pre == 4) continue; ans += dfs(pos - 1, i, limit && i == data[pos]); } if(!limit) return dp[pos][pre == 4] = ans; return ans; } ll solve(ll n) { memset(dp, 0, sizeof(dp)); int pos = 0; while(n) { data[pos++] = n % 10; n /= 10; } ll ans = dfs(pos - 1, -1, true); return ans; } int main() { ll n; int t; scanf("%d", &t); while(t--) { scanf("%lld", &n); printf("%lld\n", n - solve(n) + 1); } return 0; }
第二种方法:
假设n是123456, 当dfs到049_ _ _时,很显然,后三位可放置任意数,共有10 * 10 * 10种放置方法,这种是!limit的情况,当n是49123时,我们跑到49
_ _ _时,后边就只有123 + 1种方法。所以只要标记好limit,预处理出没有限制的情况,就可以轻松算出结果。
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll dp[30][2], kind[30], n; int data[30]; ll dfs(int pos, int pre, bool limit) { if(pos == -1) return 0; if(!limit && dp[pos][pre == 4]) return dp[pos][pre == 4]; int up = limit ? data[pos] : 9; ll ans = 0; for(int i = 0; i <= up; i++) { if(pre == 4 && i == 9) { ans = ans + (limit ? ((n % kind[pos]) + 1) : kind[pos]); } else ans += dfs(pos - 1, i, limit && i == data[pos]); } if(!limit) return dp[pos][pre == 4] = ans; return ans; } ll solve(ll k) { int pos = 0; memset(dp, 0, sizeof(dp)); while(k) { data[pos++] = k % 10; k /= 10; } return dfs(pos - 1, -1, true); } int main() { int t, i; kind[0] = 1; for(i = 1; i <= 18; i++) kind[i] = kind[i - 1] * 10; scanf("%d", &t); while(t--) { scanf("%lld", &n); printf("%lld\n", solve(n)); } }
第三种方法:
就是传统的数位dp,当时实在是太差了,这都想不出来。。
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll dp[30][30][2], n; int data[30]; ll dfs(int pos, int pre, bool sta, bool limit) { if(pos == -1 && sta) return 1; if(pos == -1 && !sta) return 0; if(!limit && dp[pos][pre == 4][sta]) return dp[pos][pre == 4][sta]; int up = limit ? data[pos] : 9; ll ans = 0; for(int i = 0; i <= up; i++) { if(pre == 4 && i == 9) ans += dfs(pos - 1, i, true, limit && i == data[pos]); else ans += dfs(pos - 1, i, sta/*注意这里是sta,而不是false, 之前出过错。*/, limit && i == data[pos]); } if(!limit) return dp[pos][pre][sta] = ans; return ans; } ll solve(ll k) { int pos = 0; memset(dp, 0, sizeof(dp)); while(k) { data[pos++] = k % 10; k /= 10; } return dfs(pos - 1, -1, false, true); } int main() { int t, i; scanf("%d", &t); while(t--) { scanf("%lld", &n); printf("%lld\n", solve(n)); } }
相关文章推荐
- HDU - 3555 bomb(数位DP) HQG_AC的博客
- HDU 3555 Bomb (数位dp)
- HDU 3555 Bomb(数位DP)
- hdu 3555 Bomb (数位dp入门)
- HDU 3555 Bomb 数位dp
- HDU 3555 Bomb (数位DP)
- HDU 3555 Bomb + HDU 2089 不要62 数位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)
- HDU 3555 Bomb(数位DP)
- HDU 3555 Bomb 数位dp
- 数位DP-HDU-3555-Bomb
- HDU 3555 Bomb 详解(数位DP入门题)
- HDU 3555 Bomb(数位dp)