51nod1042
两个数a,b(1 <= a <= b <= 10^18)
输出共10行,分别是0-9出现的次数
10 19
1
11
1
1
1
1
1
1
1
1
思路:用记忆化搜索做,当计算0的数量是要特别注意
代码
#include<stdio.h>
#include<string.h>
#define ll long long
ll dis[12];//记录位数
ll lg,len;
ll s[25];//表示10的i次方
ll ans1[12];//记录答案
ll dp[25][15][2];
ll check(ll a){ //计算分解后的前a位的值
ll i=0;
ll ans=0;
for(i=0;i<=a;i++)
ans+=dis[i]*s[i];
return ans;
}
ll dfs(ll pos,ll lg,ll k){//计算1---9的数量
if(pos<0)
return 0;
ll num=lg?dis[pos]:9;
if(!lg&&dp[pos][k][lg]!=-1)//只有没有限制的时候才能用记忆化记录的结果
return dp[pos][k][lg];
ll i,j;
ll ans=0;
for(i=0;i<=num;i++){
if(i==k){//当i等于k时,当前有k的数量就要加上后面所有可能的数字的个数 (假设是542123,当前面已经遍历完542这三位时,
//当遍历到第四位且第四位为1时,1的数量就等于23中1数量+23)
if(lg&&i==num)//注意,前面的限制不一定能对后面的计算产生影响,要看当前的i是否可以继续产生限制。
ans=ans+check(pos-1)+1+dfs(pos-1,lg&&(i==num),k);//假设是542123这个数字,当取后三位是,一共有123+1种情况(0---123)
else
ans=ans+s[pos]+dfs(pos-1,lg&&(i==num),k);// 假设是542123,当前面已经遍历到541这三位时,
//当遍历到第四位且第四位为1时,1的数量就等于100中1数量+100)
}
else
ans+=dfs(pos-1,lg&&(i==num),k);
}
if(!lg)
dp[pos][k][lg]=ans;
return ans;
}
ll dfs1(ll pos,ll lg,ll lg1){//计算零的数量
if(pos<0)
return 0;
if(!lg&&!lg1&&dp[pos][0][lg]!=-1)//只有当没有限制并且前面有非零数字时,才能用到记忆化保存的数据
{
return dp[pos][0][lg];
}
ll num=lg?dis[pos]:9;
ll i,j;
ll ans=0;
//printf("%d\n",num);
//printf("pos=%d\n",dis[pos]);
for(i=0;i<=num;i++){
//prllf("c=%d %d\n",pos,i);
if(!lg1&&i==0){
if(lg&&i==num)//注意,前面的限制不一定能对后面的计算产生影响,要看当前的i是否可以继续产生限制,在这里连续卡了几次,以为自己考虑了,但是还是没有考虑,以后做题一定要注意。
{
//printf("a=%d %d %d\n",pos,i,cal(pos)+1);
ans+=check(pos-1)+1;//同上
}
else
{
ans+=s[pos];
//printf("b=%d\n",s[pos]);
} }
//printf("%d %d %d\n",pos,i,ans);
ans+=dfs1(pos-1,lg&&(i==num),lg1&&(i==0)); }
if(!lg&&!lg1)//记忆化没有限制并且前面有非零数字的情况
dp[pos][0][lg]=ans;
return ans;
}
int main(){
ll n,m;
len=0;
scanf("%lld%lld",&n,&m);
ll i;
s[0]=1;
for(i=1;i<=18;i++)
s[i]=s[i-1]*10;
n=n-1;
while(n){//分解数字
dis[len++]=n%10;
n=n/10;
}
memset(dp,-1,sizeof(dp));
ans1[0]=-dfs1(len-1,1,1);
//printf("%d\n",ans1[0]);
for(i=1;i<=9;i++){
ans1[i]=-dfs(len-1,1,i);
}
len=0;
while(m){
dis[len++]=m%10;
m=m/10;
}
ans1[0]+=dfs1(len-1,1,1);
printf("%lld\n",ans1[0]);
for(i=1;i<=9;i++){
ans1[i]+=dfs(len-1,1,i);
printf("%lld\n",ans1[i]);
} return 0;
}
51nod1042的更多相关文章
- 【51nod-1042】数字0-9的数量
给出一段区间a-b,统计这个区间内0-9出现的次数. 比如 10-19,1出现11次(10,11,12,13,14,15,16,17,18,19,其中11包括2个1),其余数字各出现1次. Inp ...
- 51nod1042(0-x出现次数&分治)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1042 题意:中文题诶- 思路:这道题和前面的51nod100 ...
随机推荐
- POJ-2955 Brackets(括号匹配问题)
题目链接:http://poj.org/problem?id=2955 这题要求求出一段括号序列的最大括号匹配数量 规则如下: the empty sequence is a regular brac ...
- vue的优点
vue-router 单页面 虚拟DOM https://www.cnblogs.com/oldboyooxx/p/9186482.html
- Tanya and Password CodeForces - 508D (欧拉回路)
大意:给定n个长为3的子串, 求一个长为n+2的字符串包含所有子串. 相邻两个字符开一个节点, 建图跑欧拉回路, 若存在的话长度一定是$\le n+2$.
- Spring AOP实现Mysql数据库主从切换(一主多从)
设置数据库主从切换的原因:数据库中经常发生的是“读多写少”,这样读操作对数据库压力比较大,通过采用数据库集群方案, 一个数据库是主库,负责写:其他为从库,负责读,从而实现读写分离增大数据库的容错率. ...
- 常用的jquery遍历函数
1.Jquery遍历祖先 1).parent() 方法返回被选元素的直接父元素. 2).parents() 方法返回被选元素的所有祖先元素,它一路向上直到文档的根元素 (<html>) ...
- poj2117-tarjin求割点
http://poj.org/problem?id=2117 求移除一个点以及与它相邻边后,剩下的图中最大的联通子图的数量是多少. 跑一遍tarjin统计下拆除某个点剩下的子图数量即可.注意给出的图不 ...
- WDA基础八:ROWREPEATER的使用
这玩意不知道什么时候用^_^ 组件:Row-Repeater 1.新建WDA程序并激活 ZLYWDA02 2.进入VIEW,创建CONTEXT: 表:0..n 选择行:单选 初始化选择行 3.创建循 ...
- Hadoop中 Unable to load native-hadoop library for your platform... using builtin-java classes where applicable问题解决
环境 [root@vm8028 soft]# cat /etc/issue CentOS release 6.5 (Final) Kernel \r on an \m [root@vm8028 sof ...
- 三大平衡树(Treap + Splay + SBT)总结+模板[转]
Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...
- nodejs sequelize 对应数据库操作符的定义
const Op = Sequelize.Op [Op.and]: {a: } // 且 (a = 5) [Op.or]: [{a: }, {a: }] // (a = 5 或 a = 6) [Op. ...