P2602 [ZJOI2010]数字计数(特殊做法)

题目描述

给定两个正整数 a 和 b,求在 [a,b]中的所有整数中,每个数码(digit)各出现了多少次。

输入格式

仅包含一行两个整数 a,b含义如上所述。

输出格式

包含一行十个整数,分别表示 0∼9 在 [a,b] 中出现了多少次。

输入输出样例

输入
1 99
输出
9 20 20 20 20 20 20 20 20 20

说明/提示

数据规模与约定
  • 对于 30% 的数据,保证 a≤b≤106
  • 对于 100% 的数据,保证 1≤a≤b≤1012

思路

首先,这道题的常规做法应该是数位DP,但是本蒟蒻不会qwq。

  • 要求 [a,b] 中0~9个出现了多少次,我们可以分别计算0 ~ 9各出现了多少次。
  • a~b不好求,但是1 ~ a和1 ~ b还是比较好求的。ans(l,r)=ans(1,r)-ans(1,l-1);//注意是l-1
  • 于是问题就转化为了求在1~n中数字x出现了几次。
  • 我们可以暴力枚举1~n,对每个数拆分判断。但是,这显然会超时。
  • 所以我们可以考虑x在每一位各出现了多少次,然后加起来就是答案。
  • 对x在每一位出现的次数的计算,不好描述。
  • 具体看代码。

代码

#include<cstdio>
#define int long long
inline int read(){
	int x=0;char c=getchar();
	while(c>'9'||c<'0') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x;
}
int js(int n,int x){
	int s=0,i=1,l=n,m,r;//l是左边的数 m是中间的数 r是右边的数
						//例如51476 当m=6时 l=5147,r无意义
						//			当m=7时 l=514,r=6 
						//			当m=4时 l=52,r=76
						//			当m=1时 l=5,r=476
						//			当m=5时 l无意义,r=1476
	while(l)
	{
		l/=10,m=n/i%10,r=n%i;//计算l,m,r 
		if(x)//x不为0时 
		{
			if(m>x) s+=(l+1)*i;//m>x时 只需计算左边的 
			if(m==x) s+=l*i+r+1;//m=x时 左边的和右边的 
			if(m<x) s+=l*i;//m<x时 左边的 
		}
		else//x=时
			if(m) s+=l*i;//m不为0即m>x 
			else s+=(l-1)*i+r+1;
		/*精简版 
		s+=l*i;
		if(m>x&&x) s+=i;
		if(m==x&&x) s+=r+1;
		if(!m&&!x) s+=-i+r+1;*/
		i*=10;
	}
	return s;
}
signed main(){
	int l=read(),r=read();
	for(int x=0;x<=9;++x) 
		printf("%lld ",js(r,x)-js(l-1,x));
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Robin_w2321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值