BSOJ: 2697 -- 【ZJOI2010】数字计数
2016-05-22 11:24
351 查看
Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。Input
输入文件中仅包含一行两个整数a、b,含义如上所述。Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。Sample Input
1 99Sample Output
9 20 20 20 20 20 20 20 20 20Hint
30%的数据中,a<=b<=10^6;100%的数据中,a<=b<=10^12。
很裸的数位DP,好久都没刷过题了,居然搞了半小时。
我开了四维的数组,不知道还能不能优化。
p是要计算出现个数的数字(0→9)(0\to 9)
sum是之前这个数字出现次数。
flag1是判断之前有没有非0数,主要是为了针对0的计算。
建议人工模拟下,更能理解。
代码如下:
#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #include<ctime> #include<cstring> #include<algorithm> #include<queue> #include<map> using namespace std; long long F[20][10][15][2]; int c[100]; long long Cal(int x,int p,int sum,int flag1,int flag){ if(!x)return sum; if(!flag&&F[x][p][sum][flag1])return F[x][p][sum][flag1]; int k=flag?c[x]:9; long long ret=0; for(int i=0;i<=k;i++){ ret+=Cal(x-1,p,sum+((i==p)&&((flag1&&p==0)||(p!=0))),flag1||(i!=0),flag&&(i==k)); } return flag?ret:F[x][p][sum][flag1]=ret; } long long Ask(long long x,int k){ c[0]=0; while(x){c[++c[0]]=x%10;x/=10;} return Cal(c[0],k,0,0,1); } int main(){ long long a,b; scanf("%lld%lld",&a,&b); for(int i=0;i<=9;i++){ printf("%lld ",Ask(b,i)-Ask(a-1,i)); } return 0; }
相关文章推荐
- 教你如何剖析源码(转)
- java 页面错误转发提示页面 errorPage转跳报HTTP500内部服务器错误
- poj 3368 Frequent values 线段树
- Icinga2在centos7上安装流程
- POJ-2096 Collecting Bugs【概率dp】
- 二项式展开推广与微积分的关系
- 一个Laravel队列引发的报警
- Android下基于PCM的音频渲染
- Visual Studio 使用技巧, 功能与特性
- Delphi项目构成之单元文件PAS
- C#第八次上机
- OJ平台汇总
- Shell脚本学习笔记-运行控制
- DHCP源码分析-报文解析和封装
- HDU 4819 二维线段树
- 专题三 · 1018
- java命令行运行带外部jar
- Git入门简介
- 第十二周进度条
- 动态规划10之1015