fzu2113 Jason的特殊爱好(数位DP)

本文介绍了一种高效算法,用于计算指定区间内所有整数中数字1出现的总次数。通过分解数字并考虑每一位上的1可能出现的情况,该算法能够快速得出答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                           Problem 2113 Jason的特殊爱好

Accept: 314    Submit: 1012
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

Jason很喜欢数字,特别是1这个数字,因为他觉得1有特殊的含义。为了让更多的人喜欢上1,他决定出一题关于1的水题(每个人都喜欢水题)。

 Input

输入数据中有多组数据,每组数据输入为两个正数,a,b(1<=a,b<=10^18)。

 Output

输出a到b之间的整数包含多少个1。

 Sample Input

1 1000

 Sample Output

301

 

1.思路

假如统计的是5014,对于每一位数,我们假设其左边的数位l,右边的数位r;

        (1).首先枚举的是个位数:l = 501, r = 0, 当个位数是1时,左边我们可以假设位0-501到的任何一个数字,因此个位数为1时有(l+1) * 1 + r = 502种情况,属于当前位的值大于1的情况;

       (2).然后是第二位:l = 50, r = 4, 因为5014的第二位为1,所以当左边取0-49时,右边可以取0-9,而当右边取50时,左边只能是0-4,因此第二位是1时有l * 10 + (r + 1) = 505,属于当前位的值等于1的情况;

   (3).然后是第三位:l = 5, r = 14,因为5014的第三位为0 < 1,所以当第三位取1时,左边只能取0-4, 右边取0-99,有500种情况,属于当前位的值小于1的情况;

        (4).第四位:l = 0, r = 14, 当第四位取1时,有(l + 1) * 1000 = 1000种;

所以0到5014总共有2507个1;

2.代码

#include <iostream>
using namespace std;
typedef long long ll;

int digit[20];
ll p[20];

void init() {
    p[0] = 1;
    for(int i = 1; i < 19; ++ i) {
	p[i] = p[i-1] * 10;
    }
}

ll f(ll n) {
    int pos = 0;
    ll res = 0, m = n;
    while(n) {
	digit[++pos] = n % 10;
	n /= 10;
    }
    for(int i = 1; i <= pos; ++ i) {
	ll r = m % p[i-1];              // 第i位右边的数
	ll l = m / p[i];		// 第i位左边的数
	if(digit[i] > 1) {		// 当前位的值大与1的情况
	    res += (l + 1) * p[i-1];
	}
	else if(digit[i] == 1) {        // 当前位的值等于1的情况
	    res += l * p[i-1] + r + 1;
	}
	else {				// 当前位的值小于1的情况
	    res += l * p[i-1]; 
	}
    }
    return res;
}

int main() {
    ll a, b;
    init();
    while(cin >> a >> b) {
	cout << f(b) - f(a-1) << "\n";
    }
    return 0;
}

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值