【NOIP2010】【tyvj1409】数字统计加强版

49 篇文章 0 订阅
27 篇文章 0 订阅

背景

NOIP2010普及组复赛第一题加强版

描述

请统计某个给定范围[L, R]的所有整数中,数字2 出现的次数。
比如给定范围[2, 22],数字2 在数2 中出现了1 次,在数12 中出现1 次,在数20 中出
现1 次,在数21 中出现1 次,在数22 中出现2 次,所以数字2 在该范围内一共出现了6
次。

输入格式

输入共1 行,为两个正整数L 和R,之间用一个空格隔开。

输出格式

输出共1 行,表示数字2 出现的次数。

测试样例1

输入

【输入样例1】 
2 22 
【输入样例2】 
2 100

输出

输出样例1: 

输出样例2: 
20

备注

【数据范围】
0 ≤ L ≤ R≤ 10^10。NOIP2010普及组复赛——NO.1
【题解】

原本想写一个dp的代码,结果发现写成了模拟

一定范围的数里有多少个2是固定的比如说0-9,0-99,0-999这样的几位数中的2的个数都可以递推出来(其实hxy用的打标也可以)

然后就可以把数的每一位分解,然后计算出0-这一位代表的数中有多少个2,然后相加

要注意的是这个数中本身就有2的情况。如果这一位是2,那么往后所有的数都会多出一个2

求出0-l,0-r中2的个数,然后相减即可。注意如果l里本身就有2的话需要再加上2的数量

【代码】

#include<iostream>
#include<cstring>
#include<cstdio> 
using namespace std;
long long l,r,n,m,ans;
long long mi[20],f[20];
inline int doit(int now){
	long long k=now,weishu=0,tot=0,num=0,ans=0;
	while (k>0){
		num=k%10;
		weishu++;
		if (num==0){
			k/=10; continue;
		}
		tot=f[weishu];
		if (num>2) tot-=(10-num)*f[weishu-1];
		else if (num<=2){
			tot=num*f[weishu-1];
			if (num==2) tot++;
		}
		ans+=tot;
		k/=10;
	}
	return ans;
}
int main(){
	scanf("%lld%lld",&l,&r);
	mi[0]=1;
	for (int i=1;i<=10;++i) mi[i]=mi[i-1]*10;
	f[1]=2;
	for (int i=1;i<=10;++i)
	  f[i]=f[i-1]*10+mi[i-1];
	n=doit(l); long long l1=l;
	long long x=0,y=0,z=1;
	while (l>0){
		x=l%10;
		if (x==2) n+=y;
		y=x*z+y;
		z*=10;
		l/=10;
	}
	m=doit(r);
	x=0,y=0,z=1;
	while (r>0){
		x=r%10;
		if (x==2) m+=y;
		y=x*z+y;
		z*=10;
		r/=10;
	}
	ans=m-n;
	l=l1;
	while (l>0){
		int x=l%10;
		if (x==2) ans++;
		l/=10; 
	}
	printf("%lld\n",ans);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值