[ZJOI2010]数字计数

97 篇文章 0 订阅
6 篇文章 0 订阅

题目

https://www.luogu.org/problemnew/show/P2602

思路

首先区间[a,b]内的数量可转化为[1,b]-[1,a-1]。考虑求一个数码出现的次数,比如1出现的次数。我们首先想爆搜怎么写,然后加一个记忆化即可。

对于一个长度为len的数,从高位到低位枚举它每一位上的数字,然后计算1出现的次数。哪些东西要记到状态里去?第一,当前的位置len一定要记的。第二,你要记录当前数位有没有比num[len]小,是一个bool值,因为这个用来确定你枚举下一位的范围。第三,要记录当前1已经出现的次数。第四,由于前导0不能算,还需记录之前是否是前导0,也是一个bool值。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=50;
ll a,b,s1[maxn],s[maxn],num[maxn],ten[maxn],f[maxn],cnt;
void init()
{
	ten[0]=1;
	for(int i=1; i<=15; i++) f[i]=f[i-1]*10+ten[i-1],ten[i]=ten[i-1]*10;
}
void work(ll x)
{
	memset(s,0,sizeof(s)); cnt=0;
	while(x)
	{
		num[++cnt]=x%10; x/=10;
	}
	for(int i=cnt; i>=1; i--)
	{
		for(int j=0; j<=9; j++) s[j]+=f[i-1]*num[i];
		for(int j=0; j<num[i]; j++) s[j]+=ten[i-1];
		ll num2=0;
		for(int j=i-1; j>=1; j--) num2=num2*10+num[j];
        s[num[i]]+=num2+1;
        s[0]-=ten[i-1];
	}
}
int main()
{
	init();
	scanf("%lld%lld",&a,&b);
	work(b); for(int i=0; i<=9; i++) s1[i]=s[i]; 
	work(a-1); for(int i=0; i<=9; i++) printf("%lld ",s1[i]-s[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值