hdu3555 Bomb ——数位DP入门题

非 Y 不嫁゛ 提交于 2019-11-30 12:50:28

参考:http://www.cnblogs.com/liuxueyang/archive/2013/04/14/3020032.html
题意:给一个数字N,求1到N中含有49的数的个数
分析:经典数位dp。
首先定义状态:
dp[i][0]代表长度为 i 并且不含有49的数字的个数;
dp[i][1]代表长度为 i 并且不含有49,但是最高位是9的数字的个数;
dp[i][2]代表长度为 i 并且含有49的数字的个数。

转移:
dp[i][0] = dp[i-1][0] a[i] - dp[i-1][1]; 表示长度为 i 的不含有49的数字的个数等于长度为 i - 1 的不含有49的数字的个数当前的数字,因为这个位置可以填0~a[i] - 1,然后再减去长度为 i - 1 的最高位是9的数字的个数,因为如果长度为 i - 1 的最高位是9的话,那么高一位就不能填4了,否则就组成了49。

dp[i][1] = dp[i-1][0]; 表示长度为 i 的并且不含有49同时最高位是9的数字的个数等于,长度为 i - 1 的不含有49的数字的个数,因为只要在它的高一位加上一个9就可以了。

dp[i][2] = dp[i-1][2] a[i] + dp[i-1][1]; 表示长度为 i 的含有49的数字的个数等于,长度为 i - 1 的数字的个数当前的数字,再加上长度为 i - 1 的并且不含有49同时最高位是9的数字的个数,因为这个时候,只要在高一位加上一个4就可以了,这样在最高的两位就组成了一个49。

以上是预处理。
接下来步骤:从高位往低位扫描,例如第i位

  1. 首先加上 dp[i-1][2]*a[i]
  2. 若前面是否出现过49,加上 dp[i-1][0]*a[i]
  3. 若为出现49且a[i]>4,说明可以在这个位填上4,那么加上dp[i-1][1]
  4. 此刻形成49了,做标记。

其他看代码:

12345678910111213141516171819202122232425262728293031323334353637383940414243
#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;typedef long long int LL;LL dp[21][3]; unsigned long long int n; int a[25];int (){  int t; scanf("%d", &t);  memset(dp, 0, sizeof(dp));  dp[0][0] = 1;  for (int i = 1; i < 21; ++i){    dp[i][0] = dp[i-1][0] * 10 - dp[i-1][1];    dp[i][1] = dp[i-1][0];    dp[i][2] = dp[i-1][2] * 10 + dp[i-1][1];  }  while (t--){    scanf("%I64d", &n);    int len = 0; memset(a, 0, sizeof(a));    n++;    while (n){      a[++len] = n % 10; n /= 10;    }     LL ans = 0;     int last = 0;     bool flag = false;    for (int i = len; i >= 1; --i){      ans += (dp[i-1][2] * a[i]);      if (flag) ans += dp[i-1][0] * a[i];      if (!flag && a[i] > 4) {ans += dp[i-1][1];}      if (last == 4 && a[i] == 9) {flag = true;}      last = a[i];    }    printf("%I64dn", ans);  }  return 0;}

原文:大专栏  hdu3555 Bomb ——数位DP入门题


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!