前天晚上,一位研三的学长突然跑到我们宿舍,问我们一道微软笔试题。给你一个整数n,求出1到n这个区间范围内包含数字0的个数,例如当n=10的时候就只有10包含0,输出1,n=90就输出9。唯一的要求是此题不能用遍历来实现,时间负责度要比O(n)小,要是遍历显然谁都会做。

初看此题,似乎能找到规律,应该是排列组合的思想,下面是我认识的一个学数学的同学提供的思路:

用数学方法看起来应该能够解决,不过并没有尝试。在问了一个ACM大牛后,得到了一个名词“数位DP”,并且发现其实有很多与此类似的题目,都可以用数位DP的方法求解。

下面先给出数位DP的背景:

•在给定区间[A,B]内,找满足要求的数。
•要求一般和数大小无关,而与数的组成有关
•例如,递增的,1234, 2579…
•         双峰的,19280,26193…
•         含49的,49, 149, 1492… 
•         整除13的,26, 39…
•麻烦在于,规模大,位数> 100,不能枚举。
•区间往往不是整百整千,边界问题
•注意
–记忆化搜索思路清晰
–开适当空间
–寻找合适的状态,简化计算量

为了降低时间复杂度,可以借鉴传统DP中状态转换,打表这些思路,得到了数位DP:

F(A,B) = F(B,0)-F(A-1,0)

暴力+存储 = 记忆化搜索

•暴力:
•暴力枚举每一位(0..9),注意区间边界;与符号的匹配。
•dfs(i,j,k,flag)
•枚举第i位的数,匹配str[j],前一位是k,是否达到上限(flag=true,false)
•达到了上限则只能枚举0..num[i],否则可以枚举0..9
•存储
•dfs(i,j,k,flag)
•设状态与递归参数一致f[i][j][k][flag],表示当枚举到第i位的数,匹配str[j],前一位是k,是否达到上限(flag=true,false)时,满足要求的数字个数。
•dfs的过程,相当于在填充f,假设f的空间O(100*10*10*2),则dfs的时间O(20000)

针对上面几种类型的问题,数位DP解决方案如下:(具体可以看http://www.cppblog.com/Yuan/archive/2011/07/15/139299.html)

•整除13
•dfs(i, m, flag)
•枚举第i位数,前面枚举出的数模13的余数m,是否到达上限flag
•整除自身各位数CF55D
•dfs(i, m, l, flag)
•枚举第i位数,前面枚举出的数模LCM(0..9),LCM(前面枚举出的数),是否达到上限
•包含”49”
•dfs(i, k, find, flag)
•枚举第i位数,前一位是k,是否已包含”49”(find),是否达到上限
•分类讨论:前一位是否为4,当前是否已包含“49”

在这几种类型中,包含49的与微软这道题最为相近,不过要注意的是运算过程中需要把前缀0的情况剔除,最终代码如下:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long ll;#define mem(a,b) memset(a,b,sizeof(a))const int L = 20, P = 1e9+7;struct RES
{ll all, sum, cnt;RES() {}RES(int i,int j,int k):all(i),sum(j),cnt(k) {}
} dp[L];ll chkmod(ll x,ll p)
{return (x%p+p)%p;
}int d[L], n;RES dfs(int pos, int UP)
{if(pos<0){return RES(0,0,1);}if(!UP && ~dp[pos].all){return dp[pos];}RES ret(0,0,0);int up=UP?d[pos]:9;ret.all += dfs(pos-1, UP&&up==0).all;ret.all %= P;for(int i=1;i<=up;i++) {int nUP = UP&&i==up;for(int j=pos-1;j>=-1;j--) {ll tmp = dfs(j, nUP).sum + dfs(j, nUP).cnt * (pos - 1 - j);tmp %= P;ret.all += tmp;ret.all %= P;ret.sum += tmp;ret.sum %= P;ret.cnt += dfs(j, nUP).cnt;ret.cnt %= P;nUP = nUP && d[j]==0; // !!!}}if(!UP) {dp[pos] = ret;}return ret;
}ll cal(ll x)
{n=0;while(x) {d[n++]=x%10;x/=10;}return dfs(n-1,1).all;
}int main()
{mem(dp,-1);ll n;while(cin>>n) {cout<<cal(n)<<endl;}return 0;
}

数位DP--由一道微软笔试题引起相关推荐

  1. 一道微软面试题的运算过程解析

    这是一道微软的面试题: int func(x) { int countx =0; while(x) { countx ++; x = x&(x-1); } return countx; } 假 ...

  2. 答与微博前端教主在吃饭时讨论到的一道微软面试题

    加引号是因为我不知道是否真是微软面试题.题目是这样的: 有一车在某无限长公路上行驶,其起始位置和单位时间内速度均为有限大整数(正负不确定), 现有一仪器,在每一时间单位内可以探测1次车是否在指定位置, ...

  3. 一道有趣的微软笔试题

    老师d 的物理测验答案在教室里丢失了,今天那个教室上了5 堂课,老师d 上了3 堂,有可 能是a.b.c 三个同学盗窃 已知:1.a 上了两堂课 2.b 上了三堂课 3.c 上了四堂课 4.a.b.c ...

  4. ios笔试题算法_微软笔试题-Dijkstra算法

    Dijkstra算法是典型的算法.Dijkstra算法是很有代表性的算法.Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临 ...

  5. 博彦科技软件测试工程师一道C笔试题

    测试空间旗下大头针出品 前段时间学员去笔试遇到的.  北京博彦科技一道C笔试 分别填入一个语句,完成下面的函数,通过递归计算数组a[100]的前n个数之和. int sum ( int a[],int ...

  6. 关于虚函数(多态)与继承的一道搜狗笔试题

    #include<iostream> using namespace std; /*Name: Copyright: Author: Date: 25/03/13 09:12Descrip ...

  7. 微软笔试题,机器人消砖块

    我比较傻叉,居然忘了用动态规划做,用了递归,各种边界判断,而且数组稍大一点就栈溢出.递归可以剪支,稍微减少一些递归次数.不管怎么样还是贴上自己的傻叉代码吧 #include<iostream&g ...

  8. 微软笔试题 2013暑期实习笔试题目

    2019独角兽企业重金招聘Python工程师标准>>> 1: 有1000瓶水,其中1瓶是有毒的,小老鼠如果喝了有毒的水会在一个星期后死掉,问至少需要多少只小老鼠来做实验,才能够在一星 ...

  9. 微软笔试题(看到的写答案啊)

    int func(int n, int* r) { printf("n=%d *r=%d\n",n,*r);//加了个打印的东西 return n && (*r + ...

最新文章

  1. Docker桌面不再对企业用户免费,每月订阅费最高21美元,用户直接炸锅了
  2. 关于h5py的使用及数据封装实例
  3. SAP CRM Fiori应用My Note的OData调用设计
  4. html转盘游戏,html5大转盘抽奖实例源码(基于vue.js)
  5. 英伟达自动驾驶技术:用于自动驾驶汽车的端到端深度学习
  6. (22)VHDL实现比较器(二位数值)
  7. matplotlib绘制虚线_[Matplotlib习题]虚线绘图练习
  8. python numpy库安装winerror5_求问安装numpy+mkl报错FileNotFoundError: [Errno 2] No such fi
  9. spring源码解析bean定义五ContextNamespaceHandler一
  10. Python print 语句(Python 2 与 Python 3)
  11. C++编程练习(14)-------“单例模式”的实现
  12. js获取image中src属性的方法语句
  13. 视频防泄密安全解决方案
  14. c语言程序设计职工信息管理系统,C语言程序设计-职工信息管理系统.doc
  15. CopyU!v2 已经收录到腾讯软件管家!
  16. 微信小程序引入 vant UI组件库
  17. 固态硬盘与普通硬盘有哪些区别?
  18. Unity3D延迟执行功能脚本
  19. 域名注册查询批量筛选工具
  20. 中国房地产泡沫规模巨大将载入历史 面临崩溃风险

热门文章

  1. Java循环查询数据库优化
  2. MISRA-C 2004 规则解读(61S-80S)
  3. 马斯克究竟从特斯拉赚了多少钱?
  4. Python分析在德的中国程序员,告别996?
  5. 超实用CAD快捷键命令大全!
  6. 移动硬盘(USB3.0接口)插入笔记本(USB3.0接口)插入之后一会时间会提示无法识别,重新插入一次才能正常使用的问题
  7. 关于中兴软创长沙研发中心的面试
  8. android仿微信联系人索引列表
  9. 新型跨境电商平台如何选择?新手做跨境电商如何起步?
  10. Element UI 表格嵌套表单、输入框、选择框