转载自:http://blog.csdn.net/guognib/article/details/25472879

参考:

http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html

kuangbin :http://www.cnblogs.com/kuangbin/category/476047.html

http://blog.csdn.net/cmonkey_cfj/article/details/7798809

http://blog.csdn.net/liuqiyao_01/article/details/9109419

数位dp有递推和记忆化搜索的方法,比较来说记忆化搜索方法更好。通过博客一的一个好的模板,数位dp就几乎变成一个线性dp问题了。

下为博客一内容:

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

偷看了下7k+大牛的数位统计dp写法,通常的数位dp可以写成如下形式:

  1. int dfs(int i, int s, bool e) {
  2. if (i==-) return s==target_s;
  3. if (!e && ~f[i][s]) return f[i][s];
  4. int res = ;
  5. int u = e?num[i]:;
  6. for (int d = first?:; d <= u; ++d)
  7. res += dfs(i-, new_s(s, d), e&&d==u);
  8. return e?res:f[i][s]=res;
  9. }

其中:

f为记忆化数组;

i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数);

s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t);

e表示之前的数是否是上界的前缀(即后面的数能否任意填)。

for循环枚举数字时,要注意是否能枚举0,以及0对于状态的影响,有的题目前导0和中间的0是等价的,但有的不是,对于后者可以在dfs时再加一个状态变量z,表示前面是否全部是前导0,也可以看是否是首位,然后外面统计时候枚举一下位数。It depends.

于是关键就在怎么设计状态。当然做多了之后状态一眼就可以瞄出来。

注意:

不满足区间减法性质的话(如hdu 4376),不能用solve(r)-solve(l-1),状态设计会更加诡异。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

正如上面说的要注意:

前导零是否有影响。

是否满足区间减的性质。(如hdu4376,还没做,先记上)

几乎就是模板题:

模板:

UESTC 1307相邻的数差大于等于2

(不允许有前导0,前导0对计算有影响,注意前导0的处理)

  1. int dp[][];
  2. int bit[];
  3. int dfs(int pos, int s, bool limit, bool fzero)
  4. {
  5. if (pos == -) return ;///前导0的影响!!!
  6. if (!limit && !fzero && ~dp[pos][s]) return dp[pos][s];///条件判断!!!
  7. int end = limit ? bit[pos] : ;
  8.  
  9. int ans = ;
  10. for (int i = ; i <= end; i++)
  11. {
  12. if (!fzero && abs(i - s) < ) continue;///前导0的影响!!!
  13. int nows = i;
  14. ans += dfs(pos - , nows, limit && (i == end), fzero && !i);
  15. }
  16.  
  17. return limit || fzero ? ans : dp[pos][s] = ans;///条件判断!!!
  18. }
  19. int calc(int n)
  20. {
  21. if (n == ) return ;
  22. int len = ;
  23. while (n)
  24. {
  25. bit[len++] = n % ;
  26. n /= ;
  27. }
  28. return dfs(len - , , , );
  29. }
  30. int main ()
  31. {
  32. memset(dp, -, sizeof(dp));
  33. int l, r;
  34. while (cin >> l >> r)
  35. {
  36. cout << calc(r) - calc(l - ) << endl;
  37. }
  38. return ;
  39. }

其它一些题目:

Hdu3555不能出现连续的49

  1. int bit[];
  2. LL dp[][];
  3. /**
  4. 0
  5. 1
  6. 2
  7. */
  8.  
  9. /**
  10. pos为当前考虑的位置
  11. s为在pos之前已到达的状态
  12. limit当前考虑的数字是否有限制,即之前已确定的数是否为n的前缀
  13. */
  14. LL dfs(int pos, int s, bool limit)
  15. {
  16. if (pos == -) return s == ;
  17. if (!limit && ~dp[pos][s]) return dp[pos][s];
  18. int end = limit ? bit[pos] : ;///limit选择
  19. LL ans = ;
  20.  
  21. for (int i = ; i <= end; i++)
  22. {
  23. int nows;
  24. if (s == )
  25. {
  26. if (i == ) nows = ;
  27. else nows = ;
  28. }
  29. else if (s == )
  30. {
  31. if (i == ) nows = ;
  32. else if (i == ) nows = ;
  33. else nows = ;
  34. }
  35. else if (s == ) nows = ;
  36.  
  37. ans += dfs(pos - , nows, limit && i == end);
  38. }
  39.  
  40. return limit ? ans : dp[pos][s] = ans;///limit选择
  41. }
  42.  
  43. LL calc(LL n)
  44. {
  45. ///
  46. int len = ;
  47. while (n)
  48. {
  49. bit[len++] = n % ;
  50. n /= ;
  51. }
  52. ///
  53. return dfs(len - , , );
  54. }
  55. int main ()
  56. {
  57. memset(dp, -, sizeof(dp));
  58. int T;
  59. RI(T);
  60. LL n;
  61. while (T--)
  62. {
  63. cin >> n;
  64. cout << calc(n) << endl;
  65. }
  66. return ;
  67. }

hdu2089 不要62

  1. int dp[][];
  2. int bit[];
  3. int dfs(int pos, int s, int limit, bool first)
  4. {
  5. if (pos == -) return s == ;
  6. if (!limit && ~dp[pos][s]) return dp[pos][s];
  7. int end = limit ? bit[pos] : ;
  8. // int be = first ? 1 : 0;
  9.  
  10. int ans = ;
  11. for (int i = ; i <= end; i++)
  12. {
  13. int nows = s;
  14. if (s == )
  15. {
  16. if (i == ) nows = ;
  17. else if (i == ) nows = ;
  18. }
  19. if (s == )
  20. {
  21. if (i == || i == ) nows = ;
  22. else if (i == ) nows = ;
  23. else nows = ;
  24. }
  25. if (i == ) nows = ;
  26.  
  27. ans += dfs(pos - , nows, limit && (i == end), first && !i);
  28. }
  29.  
  30. return limit ? ans : dp[pos][s] = ans;
  31. }
  32. int calc(int n)
  33. {
  34. int tmp = n;
  35. if (n == ) return ;
  36. int len = ;
  37. while (n)
  38. {
  39. bit[len++] = n % ;
  40. n /= ;
  41. }
  42. return tmp - dfs(len - , , , );
  43. }
  44. int main ()
  45. {
  46. memset(dp, -, sizeof(dp));
  47. int l, r;
  48. // for (int i = 1; i <= 100; i++)
  49. // cout << i << ' ' << calc(i) << endl;
  50. while (cin >> l >> r)
  51. {
  52. if (l + r == ) break;
  53. // cout << calc(r) << ' ' << calc(l - 1) << endl;
  54. cout << calc(r) - calc(l - ) << endl;
  55. }
  56.  
  57. return ;
  58. }

UESTC 1307相邻的数差大于等于2

(注意前导0的处理)

  1. int dp[][];
  2. int bit[];
  3. int dfs(int pos, int s, bool limit, bool fzero)
  4. {
  5. if (pos == -) return ;///前导0的影响!!!
  6. if (!limit && !fzero && ~dp[pos][s]) return dp[pos][s];///条件判断!!!
  7. int end = limit ? bit[pos] : ;
  8.  
  9. int ans = ;
  10. for (int i = ; i <= end; i++)
  11. {
  12. if (!fzero && abs(i - s) < ) continue;///前导0的影响!!!
  13. int nows = i;
  14. ans += dfs(pos - , nows, limit && (i == end), fzero && !i);
  15. }
  16.  
  17. return limit || fzero ? ans : dp[pos][s] = ans;///条件判断!!!
  18. }
  19. int calc(int n)
  20. {
  21. if (n == ) return ;
  22. int len = ;
  23. while (n)
  24. {
  25. bit[len++] = n % ;
  26. n /= ;
  27. }
  28. return dfs(len - , , , );
  29. }
  30. int main ()
  31. {
  32. memset(dp, -, sizeof(dp));
  33. int l, r;
  34. while (cin >> l >> r)
  35. {
  36. cout << calc(r) - calc(l - ) << endl;
  37. }
  38. return ;
  39. }

POJ 3252  Round Number (组合数)!!!

拆成2进制,在记录0和1的个数

求区间[l,r]中,满足传化成2进制后,0的个数>=1的个数的,数字的个数

  1. int dp[][][];
  2. int bit[];
  3. int dfs(int pos, int num0, int num1, bool limit, bool fzero)
  4. {
  5. if (pos == -) return num0 >= num1;///前导0的影响!!!
  6. if (!limit && !fzero && ~dp[pos][num0][num1]) return dp[pos][num0][num1];///条件判断!!!
  7. int end = limit ? bit[pos] : ;
  8.  
  9. int ans = ;
  10. for (int i = ; i <= end; i++)
  11. {
  12. int new0, new1;
  13. if (fzero)
  14. {
  15. new0 = , new1 = ;
  16. if (i) new1 = ;
  17. }
  18. else
  19. {
  20. new0 = num0, new1 = num1;
  21. if (i) new1++;
  22. else new0++;
  23. }
  24. ans += dfs(pos - , new0, new1, limit && (i == end), fzero && !i);
  25. }
  26. return limit || fzero ? ans : dp[pos][num0][num1] = ans;///条件判断!!!
  27. }
  28. int calc(int n)
  29. {
  30. if (n == ) return ;
  31. int len = ;
  32. while (n)
  33. {
  34. bit[len++] = n % ;
  35. n /= ;
  36. }
  37. return dfs(len - , , , , );
  38. }
  39. int main ()
  40. {
  41. memset(dp, -, sizeof(dp));
  42. int l, r;
  43. while (cin >> l >> r)
  44. {
  45. cout << calc(r) - calc(l - ) << endl;
  46. }
  47. return ;
  48. }

hdu3886求满足符号串的数字个数!!!

统计满足和指定 升降字符串 匹配的个数

  1. int dp[][][];
  2. int bit[];
  3. char s[];
  4. char a[], b[];
  5. int ns;
  6.  
  7. bool ok(int r, int a, int b)
  8. {
  9. if (s[r] == '/') return a < b;
  10. else if (s[r] == '-') return a == b;
  11. else if (s[r] == '\\') return a > b;
  12. }
  13. int dfs(int pos, int r, int pre, bool limit, bool prezero)
  14. {
  15. if (pos == -) return (r == ns);
  16. if (!limit && !prezero && ~dp[pos][r][pre]) return dp[pos][r][pre];
  17. int end = limit ? bit[pos] : ;
  18. int ans = ;
  19.  
  20. for (int i = ; i <= end; i++)
  21. {
  22. if (prezero)
  23. {
  24. ans += dfs(pos - , r, i, limit && (i == end), prezero && (!i));
  25. }
  26. else
  27. {
  28. if (r < ns && ok(r, pre, i))///优先考虑向后拓展
  29. ans += dfs(pos - , r + , i, limit && (i == end), );
  30. else if (r > && ok(r - , pre, i))
  31. ans += dfs(pos - , r, i, limit && (i == end), );
  32. }
  33. ans %= MOD;
  34. }
  35. if (!limit && !prezero) dp[pos][r][pre] = ans;
  36. return ans;
  37. }
  38. int calc(char a[], bool dec)
  39. {
  40.  
  41. int n = strlen(a);
  42. int len = , tmp = ;
  43. while (a[tmp] == '') tmp++;
  44. for (int i = n - ; i >= tmp; i--)
  45. {
  46. bit[len++] = a[i] - '';
  47. }
  48. if (dec && len > )
  49. {
  50. for (int i = ; i < len; i++)
  51. {
  52. if (bit[i])
  53. {
  54. bit[i]--;
  55. break;
  56. }
  57. else bit[i] = ;
  58. }
  59. }
  60. return dfs(len - , , , , );
  61. }
  62.  
  63. int main ()
  64. {
  65. while (scanf("%s", s) != EOF)
  66. {
  67. memset(dp, -, sizeof(dp));
  68. ns = strlen(s);
  69. scanf("%s%s", a, b);
  70. printf("%08d\n", (calc(b, ) - calc(a, ) + MOD) % MOD);
  71. }
  72. return ;
  73. }

HDU 3709 平衡数

  1. LL dp[][][];
  2. ///力矩最大为不超过10*20*10;
  3. int bit[];
  4.  
  5. LL dfs(int pos, int r, int sum, int e)
  6. {
  7. if (pos == -) return sum == ;
  8. if (sum < ) return ;
  9. if (!e && ~dp[pos][r][sum]) return dp[pos][r][sum];
  10. int end = e ? bit[pos] : ;
  11. LL ans = ;
  12. for (int i = ; i <= end; i++)
  13. {
  14. ans += dfs(pos - , r, sum + i * (pos - r), e && (i == end));
  15. }
  16. if (!e) dp[pos][r][sum] = ans;
  17. return ans;
  18. }
  19.  
  20. LL calc(LL n)
  21. {
  22. if (n < ) return ;
  23. int len = ;
  24. while (n)
  25. {
  26. bit[len++] = n % ;
  27. n /= ;
  28. }
  29. LL ans = ;
  30. for (int i = ; i < len; i++)///需要枚举支点
  31. ans += dfs(len - , i, , );
  32. return ans - (len - );
  33. }
  34. int main ()
  35. {
  36. memset(dp, -, sizeof(dp));
  37. int t;
  38. LL l, r;
  39. RI(t);
  40. while (t--)
  41. {
  42. scanf("%I64d%I64d", &l, &r);
  43. printf("%I64d\n", calc(r) - calc(l - ));
  44. }
  45.  
  46. return ;
  47. }

HDU4352严格上升子序列的长度为K的个数。!!!

最长上升子序列结合,通过集合(1<<10)来处理

  1. LL dp[][ << ][];
  2. int bit[];
  3. int k;
  4. int getnews(int s, int x)
  5. {
  6. for(int i=x;i<;i++)
  7. if(s&(<<i))return (s^(<<i))|(<<x);
  8. return s|(<<x);
  9. }
  10. int getnum(int s)
  11. {
  12. int ret = ;
  13. while (s)
  14. {
  15. if (s & ) ret++;
  16. s >>= ;
  17. }
  18. return ret;
  19. }
  20. LL dfs(int pos, int s, int e, int z)
  21. {
  22. if (pos == -) return getnum(s) == k;
  23. if (!e && ~dp[pos][s][k]) return dp[pos][s][k];
  24. int end = e ? bit[pos] : ;
  25. LL ans = ;
  26.  
  27. for (int i = ; i <= end; i++)
  28. {
  29. int news = getnews(s, i);
  30. if (z && !i) news = ;
  31. ans += dfs(pos - , news, e && (i == end), z && (!i));
  32. }
  33. if (!e) dp[pos][s][k] = ans;
  34. return ans;
  35. }
  36.  
  37. LL calc(LL n)
  38. {
  39. int len = ;
  40. while (n)
  41. {
  42. bit[len++] = n % ;
  43. n /= ;
  44. }
  45. return dfs(len - , , , );
  46. }
  47.  
  48. int main ()
  49. {
  50. LL n, m;
  51. memset(dp, -, sizeof(dp));
  52. int t;
  53. scanf("%d", &t);
  54. int nc = ;
  55. while (t--)
  56. {
  57. cin >> n >> m >> k;
  58. printf("Case #%d: ", nc++);
  59. cout << calc(m) - calc(n - ) << endl;
  60. }
  61. return ;
  62. }

!!!是比较不错,待看的题

比较还好的处理的题目:

Codeforces 55D Beautiful numbers!!!

spoj 10606 Balanced Numbers

ac自动机和数位dp结合(!!!):

hdu4376!!!(区间不可减???)
ZOJ3494 BCD Code(AC自动机+数位DP)!!!

整除和简单统计:

HDU4507 和7无关数的平方和!!!

HDU 3652 出现13,而且能被13整除

LightOJ 1068 能被K整数且各位数字之和也能被K整除的数

light OJ 1140两个数之间的所有数中零的个数。

lightoj 1032  二进制数中连续两个‘1’出现次数的和

其它:
LightOJ1205求区间[a,b]的回文数个数。
ural 1057 数位统计
codeforces215E周期数
codeforces258B在1-m中任选7个数,要使前六个数字中的“4”,"7"之和小于第七个的,
Zoj2599 数位统计(见题意)
zoj3162分形、自相似

[转]数位dp小记的更多相关文章

  1. 【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP

    [BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁 ...

  2. bzoj1026数位dp

    基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...

  3. uva12063数位dp

    辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...

  4. HDU2089 不要62[数位DP]

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  5. 数位DP GYM 100827 E Hill Number

    题目链接 题意:判断小于n的数字中,数位从高到低成上升再下降的趋势的数字的个数 分析:简单的数位DP,保存前一位的数字,注意临界点的处理,都是套路. #include <bits/stdc++. ...

  6. 数位dp总结

    由简单到稍微难点. 从网上搜了10到数位dp的题目,有几道还是很难想到的,前几道基本都是模板题,供入门用. 点开即可看题解. hdu3555 Bomb hdu3652 B-number hdu2089 ...

  7. 数位DP入门

    HDU 2089 不要62 DESC: 问l, r范围内的没有4和相邻62的数有多少个. #include <stdio.h> #include <string.h> #inc ...

  8. 数位DP之奥义

    恩是的没错数位DP的奥义就是一个简练的dfs模板 int dfs(int position, int condition, bool boundary) { ) return (condition ? ...

  9. 浅谈数位DP

    在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...

随机推荐

  1. [NOIP2001提高组]CODEVS1014 Car的旅行路线(最短路)

    最短路,这个不难想,但是要为它加边就有点麻烦..还好写完就过了(虽然WA了一次,因为我调试用的输出没删了..),不然实在是觉得挺难调的.. ------------------------------ ...

  2. dubbo架构演变之路

    背景 (#) 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时, ...

  3. app微信支付服务器端php demo

    class Wxpay { /* 配置参数 */ private $config = array( 'appid' => "wxc92b12277f277355", /*微信 ...

  4. 利用python进行数据分析之pandas库的应用(二)

    本节介绍Series和DataFrame中的数据的基本手段 重新索引 pandas对象的一个重要方法就是reindex,作用是创建一个适应新索引的新对象 >>> from panda ...

  5. [LeetCode]题解(python):007-Reverse Integer

    题目来源: https://leetcode.com/problems/reverse-integer/ 题意分析: 这道题目很简单,就是将一个数反转,123变321,-123变321. 题目思路: ...

  6. vs2013 cpu占用100%问题

    是由于显卡驱动支持wpf有问题 更新驱动或设置里取消自动调节视觉效果 http://support.microsoft.com/kb/2894215

  7. javascript Node操作

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. 一个高效过滤非UTF8字符的C函数(也可用来判断是否utf8)

    /* UTF-8 valid format list: 0xxxxxxx 110xxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 11110xxx 10xxxxxx ...

  9. spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jetty,Restful-jersey等)

    在实战中学习,模仿博客园的部分功能.包括用户的注册,登陆:发表新随笔,阅读随笔:发表评论,以及定时任务等.Entity层设计3张表,分别为user表(用户),essay表(随笔)以及comment表( ...

  10. SPOJ1811最长公共子串问题(后缀自动机)

    题目:http://www.spoj.com/problems/LCS/ 题意:给两个串A和B,求这两个串的最长公共子串. 分析:其实本题用后缀数组的DC3已经能很好的解决,这里我们来说说利用后缀自动 ...