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

背景

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
#include
#include 
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);
}



你可能感兴趣的:(题解,NOIP,模拟)