hdu3652 数位dp经典

来源:互联网 发布:其恕乎是什么意思 编辑:程序博客网 时间:2024/06/14 05:26

*Get:非常经典的数位dp,用模板化limit dfs的方式写比较直接,状态定义见代码注解.这里发现这样模板化之后,
*只需要每次都来倒着拆分这个数为数字,然后倒着扩展(还原回去是从左到右扩展),就可以解决连续数字串,固定
*余数的问题.而且加入的limit让最后的扩展变得非常模板化,十分简洁.试想这个写成递推,会非常繁杂的解决limit问题.

/**********************jibancanyang************************** *Author        :jibancanyang *Created Time  : 二  4/19 00:05:58 2016 *File Name     : hdu3652.cpp *Problem:数位dp经典***********************1599664856@qq.com**********************/#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <cmath>#include <cstdlib>#include <ctime>#include <stack>using namespace std;typedef pair<int, int> pii;typedef long long ll;typedef unsigned long long ull;vector<int> vi;#define pr(x) cout << #x << ": " << x << "  " #define pl(x) cout << #x << ": " << x << endl;#define xx first#define yy second#define sa(n) scanf("%d", &(n))#define rep(i, a, n) for (int i = a; i < n; i++)#define vep(c) for(decltype((c).begin() ) it = (c).begin(); it != (c).end(); it++) const int mod = 13, INF = 0x3fffffff, maxn = 1e5 + 12;int bit[11], n, dp[11][13][2][2], t, x;//扩展到第len位, 余数为res, 到目前为止是否有13出现, 上一位是否为1, 本位是否有限制int dfs(int len, int res, bool have, bool cur, bool limit) {    //pr(len), pr(res), pr(have), pr(cur), pl(limit);    if (len == -1) return have && res == 0;    if (!limit && dp[len][res][have][cur] != -1) return dp[len][res][have][cur];    int m = limit ? bit[len] : 9;    int ret = 0;    for (int i = 0; i <= m; i++) {        ret += dfs(len - 1, (res * 10 % mod + i) % mod, have || (cur && i == 3), i == 1, limit && i == m);    }    if (!limit) dp[len][res][have][cur] = ret;    return ret;}int solve(int n) {    t = 0, x = n;    while (x) {        bit[t++] = x % 10;        x /= 10;    }    return dfs(t - 1, 0, false, false, true);}int main(void){#ifdef LOCAL    //freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);#endif    cin.sync_with_stdio(false);    memset(dp, -1, sizeof(dp));    while (cin >> n) {        cout << solve(n) << endl;    }    return 0;}

笔者的另一种思路:

这里的res记录不符合常规dp思想,是因为取余的性质,记录左边已得,还是右边需求都一样。

/**********************jibancanyang************************** *Author*        :jibancanyang *Created Time*  : 四  6/16 21:00:50 2016**Problem**:**Analyse**:**Get**:**Code**:***********************1599664856@qq.com**********************/#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <cmath>#include <cstdlib>#include <ctime>#include <stack>using namespace std;typedef pair<int, int> pii;typedef long long ll;typedef unsigned long long ull;typedef vector<int> vi;#define pr(x) cout << #x << ": " << x << "  " #define pl(x) cout << #x << ": " << x << endl;#define pri(a) printf("%d\n",(a))#define xx first#define yy second#define sa(n) scanf("%d", &(n))#define sal(n) scanf("%lld", &(n))#define sai(n) scanf("%I64d", &(n))#define vep(c) for(decltype((c).begin() ) it = (c).begin(); it != (c).end(); it++) const int mod = int(1e9) + 7, INF = 0x3f3f3f3f;const int maxn = 1e5 + 13;int bits[11];int dp[11][10][2][13];//have的意义是是否还需要13的出现。int dfs(int len, int high, bool have, bool limit, int res) {    if (len == 0) {        return !have && (res == 0);    }    if (!limit && dp[len][high][have][res] != -1) return dp[len][high][have][res];    int m = limit ? bits[len] : 9;    int ret = 0;    for (int i = 0; i <= m; i++) {        if ( (high == 1 && i  == 3) || !have ) ret += dfs(len - 1, i, false, limit && i == m, (res * 10 + i) % 13 );        else  ret += dfs(len - 1, i, true, limit && i == m, (res * 10 + i) % 13);    }    if (!limit) dp[len][high][have][res] = ret;    return ret;}int solve(int n) {    int t = 1;    while (n) {        bits[t++] = n % 10;        n /= 10;    }    bits[t] = 9;    return dfs(t - 1, 9, true, true, 0);}int main(void){#ifdef LOCAL    freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);#endif    int r;    memset(dp, -1, sizeof(dp));    while (~sa(r)) {        pri(solve(r));    }    return 0;}
0 0
原创粉丝点击