UVa-11038 How Many O's? (整数区间分解)

这类题大的方向都是写一个函数f(n)表示1到n中所有的数一共有多少个0,那么最终的答案就是f(n)-f(m-1)所以关键就是如何写f,这是一个神奇的方法。。。

首先比如n=12345,把其中一位数假设为0,那么这位数左边的种数*右边的种数就等于当这位数确实为0时所需要写下的0的个数

具体一点:

mid     left             right                                                   x                 ans

          12345          0                                                      1                  0

5        1234            0+5*1                                               10                1234*1

4        123              0+5*1+4*10                                     100               1234*1+123*10  //比如此时左边有1-123共123个,右边有0-9共10个,乘法原理相乘可得

3        12                0+5*1+4*10+3*100                          1000            1234*1+123*10+12*100

2        1                  0+5*1+4*10+3*100+2*2000             10000          1234*1+123*10+12*100+1*1000


上述情况因为原数的某一位不为0,所以当我们把这一位假设为0后,之后得到的数无论如何也不可能大于原数,比如(1-123)0(0-9)无论如何也不可能大于12345

但是如果当原数的某一位确实为0时,比如12305,为了保证所假设得到的数不大于原数,这时候答案就为122*10+6 即前122位*10不变,当左边为123时,右边只能小于等于5


此外我们假设位0的右边的位数是一定的,比如120345,0右边必定是从000到345即一定会有三位数,当假设位前移时如10x345,无论x是否为0,此时假设位0的右边有4位数,与之前的三位数肯定不一样,所以整个数也不一样,所以不用担心数字会重复

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define mod 1000000007
using namespace std;

ll solve(ll left){
	ll mid,ans=0,right=0,x=1;
	while(left>=10){
		mid=left%10;
		left/=10;
		if(mid) ans+=left*x;
		else ans+=(left-1)*x+(right+1);
		right+=mid*x;
		x*=10;
	}
	return ans;
}

int main(){
	ll m,n;
	while(cin>>m>>n&&m!=-1&&n!=-1){
		cout<<solve(n)-solve(m-1)<<endl;
	}
	return 0;
} 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值