数位dp有着很明显的特点,一般来说是给定区间[l,r]求满足某种条件区间中的数有多少个

朴素解法一般是O(n)的而n往往很大(10^8起步)

这时候我们就要想办法优化,于是就有了数位dp

数位有两个基本的原则

  1. 对于区间数的个数,我们转化为前缀和做(即ans=sum(r)-sum(l-1))

  2. 逐位确定

我认为第二条很关键,可以说是数位dp的精髓

一般来说数位dp分两步

  1. 打表 形如f[i,j]到有i位且最高位为j的满足条件的个数

  2. 统计前缀和

统计前缀和我们需要用到一个非常重要的结论

对于任意一个小于n的数,从高位到低位,必然出现了某一位小于n的那一位

这样我们就可以不受n的限制,用数位开始处理

以bzoj1026这道经典的题目为例

 var f:array[..,..] of longint;
    d:array[..] of longint;
    l,r,t,i,j,k:longint; function get(n:longint):longint;
  var i,s,x,j:longint;
  begin
    if (n>=) and (n<=) then exit(n);
    fillchar(d,sizeof(d),);
    s:=;
    while n<> do
    begin
      inc(s);
      d[s]:=n mod ;
      n:=n div ;
    end;
    get:=;
    for i:= to s- do   //统计位数小于n的位数的满足条件的数目
      for j:= to do
        get:=get+f[i,j];
//注意这里是不能直接加前导为0的数组,因为我们在计算前导为0的时候,实际上舍掉了后一位为0~的情况
    for i:=s downto do  //从高到低逐位统计位数为n的位数且小于n的满足条件的个数
    begin
      if i<> then x:=d[i]- else x:=d[i]; //小细节,注意n本身也可能是
      for j:= to x do   //当前位小于n的这位的满足条件的数
      begin
        if (i=s) and (j=) then continue;
        if (s=i) or (abs(j-d[i+])>=) then
          get:=get+f[i,j];
      end;
      if (s<>i) and (abs(d[i+]-d[i])<) then break;  //如果逐位统计n本身出现了不满足的情况,那显然要直接退出
    end;
  end; begin
  readln(l,r);
  t:=trunc(ln(r)/ln())+;
  for i:= to do   //题目的特殊要求
    f[,i]:=;
  for i:= to t do  //计算f[i,j]
  begin
    for j:= to do  //注意要包含前导为0的状况 
      for k:= to do
        if abs(j-k)>= then   
          f[i,j]:=f[i,j]+f[i-,k];
  end;
  writeln(get(r)-get(l-));
end.

bzoj1026

(话说我第一次拍这道题花了3h,实在太渣……)

当然我们也不能拘泥于这种套路,我觉得

当表打了没什么用的时候我们可以直接逐位计算,如poj3286(统计0的个数)

这里我们讨论,每一位对0的贡献度

 var d:array[..] of int64;
    i:longint;
    l,r:int64; function count(n:int64):int64;
  var i,t:longint;
      x,y:int64;
  begin
    for i:= to do
      if (n<d[i]) then break;
    t:=i-;
    count:=;
    for i:= to t do
    begin
      x:=n div d[i];    //当前位前面所组成的数
      y:=n mod d[i-];  //当前位后面所组成的数
      if (n div d[i-] mod )= then  //当前位
        count:=count+d[i-]*(x-)+y+   
//如果是x0y的情况,是第k位时,我们分2种情况讨论
  当小于n的数是p0q的,p∈[,x-],那么这个位上的0可以贡献(x-)*^(k-)
  当这个小于等于n的数是x0q, q∈[,y]那么这个位上的0可以贡献y+
      else count:=count+d[i-]*x;
//如果当前位不是0,那显然比n小的数中肯定存在当前位为0的;
设数为p0q, p∈[,x], q∈[,^(k-)-] 因为当前位已经小于则显然可以贡献x*^(k-)
    end;
  end; begin
  d[]:=;
  for i:= to do
    d[i]:=d[i-]*;
  readln(l,r);
  while (l<>-) do
  begin
    if l= then writeln(count(r))
    else writeln(count(r)-count(l-));
    readln(l,r);
  end;
end.

poj3286

数位dp需要大量的思考,有时候看起来对的实际上是错的

但由于这种题目暴力,数据都非常好弄

所以一定要孜孜不倦的对拍,恩恩

初探数位dp的更多相关文章

  1. 数位dp入门 hdu2089 不要62

    数位dp入门 hdu2089 不要62 题意: 给定一个区间[n,m] (0< n ≤ m<1000000),找出不含4和'62'的数的个数 (ps:开始以为直接暴力可以..貌似可以,但是 ...

  2. [bzoj1833][ZJOI2010]count 数字计数——数位dp

    题目: (传送门)[http://www.lydsy.com/JudgeOnline/problem.php?id=1833] 题解: 第一次接触数位dp,真的是恶心. 首先翻阅了很多很多一维dp,因 ...

  3. 数位dp初探

    我这种蒟蒻就一直不会写数位dp.. 于是开了个坑.. 1833: [ZJOI2010]count 数字计数 这道被KPM大爷说是入门题..嗯似乎找找规律然后减掉0的情况后乱搞就可以了..(但是还是写了 ...

  4. 数位类统计问题--数位DP

    有一类与数位有关的区间统计问题.这类问题往往具有比较浓厚的数学味道,无法暴力求解,需要在数位上进行递推等操作.这类问题往往需要一些预处理,这就用到了数位DP. 本文地址:http://www.cnbl ...

  5. 动态规划——数位dp

    通过先前在<动态规划——背包问题>中关于动态规划的初探,我们其实可以看到,动态规划其实不是像凸包.扩展欧几里得等是具体的算法,而是一种在解决问题中决策的思想.在不同的题目中,我们都需要根据 ...

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

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

  7. bzoj1026数位dp

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

  8. uva12063数位dp

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

  9. HDU2089 不要62[数位DP]

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

随机推荐

  1. nodejs npm install全局安装和本地安装的区别

    npm的包安装分为本地安装(local).全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,比如:代码如下:复制代码npm install # 本地安装npm install - ...

  2. NodeJS包管理工具——npm入门

    如今每个语言体系中都有一个包管理工具,PHP的Composer,Ruby的gem,Python的pip,Java的Maven……当然还有Node.js的npm.有的人会奇怪为何要引入又一个新东西来让我 ...

  3. ContextMenuStrip控件

    设置单击窗体右键菜单 注意如果想在form1中显示右键菜单,那么要设置form1的属性

  4. EF当实体模型与数据库的架构不同时要删除数据库时的报错问题

    当使用的EF的时候,我们都知道EF当实体模型与数据库的架构不同时要删除数据库,这是会把错: 无法创建与 'master' 数据库之间的连接,这是因为已打开原始数据库连接,并且已从连接字符串中删除凭据. ...

  5. IE9下Coolite.Ext出现createContextualFragment错误

    解决Ext在IE9上报错“createContextualFragment”,只需要在使用Coolite.Ext页面加入如下代码即可: if ((typeof Range !== "unde ...

  6. Oracle 常用操作

    修改数据库表名:rename [old-table] to [new-table]; while循环添加测试数据: declare     i int:=1;     begin     while ...

  7. Contest2037 - CSU Monthly 2013 Oct (problem A :Small change)

    [题解]:二进制拆分 任意一个整数都可以拆分成 2^0 + 2^1 + 2^2 + 2^3 + ....+ m [code]: #include <iostream> #include & ...

  8. 第二好用的时间日期选择插件(jscal)

    这个是第二好用的了,支持鼠标滚动选择时间.功能很强大,文档:http://www.dynarch.com/jscal/ 效果图: <!DOCTYPE html PUBLIC            ...

  9. 3140:[HNOI2013]消毒 - BZOJ

    题目描述 Description 最近在生物实验室工作的小 T 遇到了大麻烦. 由于实验室最近升级的缘故,他的分格实验皿是一个长方体,其尺寸为 a*b*c,a.b.c均为正整数.为了实验的方便,它被划 ...

  10. ExtJS4.2学习(20)动态数据表格之前几章总结篇1(转)

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2014-02-18/196.html --------------- ...