hi.数字统计

[NOIP2010 普及组] 数字统计

题目描述

请统计某个给定范围 [ L , R ] [L, R] [L,R] 的所有整数中,数字 2 2 2 出现的次数。

比如给定范围 [ 2 , 22 ] [2, 22] [2,22],数字 2 2 2 在数 2 2 2 中出现了 1 1 1 次,在数 12 12 12 中出现 1 1 1 次,在数 20 20 20 中出现 1 1 1 次,在数 21 21 21 中出现 1 1 1 次,在数 22 22 22 中出现 2 2 2 次,所以数字 2 2 2 在该范围内一共出现了 6 6 6 次。

输入格式

2 2 2 个正整数 L L L R R R,之间用一个空格隔开。

输出格式

数字 2 2 2 出现的次数。

样例 #1

样例输入 #1

2 22

样例输出 #1

6

样例 #2

样例输入 #2

2 100

样例输出 #2

20

提示说明

1 ≤ L ≤ R ≤ 100000 1 ≤ L ≤R≤ 100000 1LR100000

NOIP2010 普及组 第一题

代码内容

// #include <iostream>
// #include <algorithm>
// #include <cstring>
// #include <stack>//栈
// #include <deque>//队列
// #include <queue>//堆/优先队列
// #include <map>//映射/*  */
// #include <unordered_map>//哈希表
// #include <vector>//容器,存数组的数,表数组的长度
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
    ll a,b;
    cin>>a>>b;

    ll s=0;
    for(ll i=a;i<=b;i++)
    {
        ll n=i;
        while(n!=0)
        {
            if(n%10==2) s++;
            n/=10;
        }
    }
    
    cout<<s<<endl;
    return 0;
}
### 回答1: 这个问题可以通过数位DP来解决。 我们可以将数字拆分成若干位,然后从高位到低位依次考虑每一位上数字2出现次数。 具体来说,我们可以设f[i][j]表示考虑到第i位,当前数字为j时,数字2出现次数。其i的范围是[1, k],j的范围是[0, 9]。 我们可以通过以下转移来计算f[i][j]: 1. 如果j < 2,则f[i][j] = f[i-1][j] * 10 + 10^(i-1)。 这个转移表示如果当前位上的数字小于2,那么前面的数字可以任意填,而当前位上的数字只能填0~j-1,因此我们需要将前面的数字乘以10,然后再加上当前位上数字为0~j-1时数字2出现次数。 2. 如果j = 2,则f[i][j] = f[i-1][j] * 10 + l%(10^(i-1)) + 1。 这个转移表示如果当前位上的数字为2,那么前面的数字可以任意填,而当前位上的数字可以填0~2,因此我们需要将前面的数字乘以10,然后再加上当前位上数字为0~2时数字2出现次数。注意,我们还需要加上l%(10^(i-1))+1,表示当前位上数字为2时,l到r范围内的数字,最高位到第i位的数字可以任意填,而第i+1位及以后的数字必须与r相同,因此我们需要将l%(10^(i-1))+1加上。 3. 如果j > 2,则f[i][j] = f[i-1][j] * 10 + 10^(i-1)。 这个转移表示如果当前位上的数字大于2,那么前面的数字可以任意填,而当前位上的数字只能填0~9,因此我们需要将前面的数字乘以10,然后再加上当前位上数字为0~9时数字2出现次数。 最终的答案就是f[k][9]-f[k][0],表示考虑到第k位时,所有数字数字2出现次数。 时间复杂度 这个算法的时间复杂度是O(logr),其r是给定范围的右端点。 ### 回答2: 此题可以采用数位DP的思想,将数字转化为字符串,按位枚举,具体实现步骤如下: 首先,我们需要计算出每一位上数字2出现次数。假设当前枚举到第i位,数字范围是[0, 9],我们需要先算出2出现在这一位的次数cnt,其有以下几种情况: 1. 若当前位的数字小于2,则2只能出现在更高位,此时2出现次数等于更高位数的取值*当前位数位数,即 cnt += (high * digit); 2. 若当前位的数字等于2,则2既可以出现在更高位,也可以出现在更低位,此时2出现次数等于更高位数的取值*当前位数位数+1,即 cnt += (high * digit + low + 1); 3. 若当前位的数字大于2,则2只能出现在更低位,此时2出现次数等于(更高位数的取值+1)*当前位数位数,即 cnt += ((high + 1) * digit)。 在计算每一位上数字2出现次数之后,我们只需要将每一位的cnt累加起来即可得到[l, r]区间内2出现次数的总和。 具体的代码实现如下: ### 回答3: 对于这个问题,我们需要分析各个位数上数字2出现的情况,然后累加得到总次数。 首先考虑个位上的情况,我们可以先将[l, r]的所有数变成以1为个位的形式,如将1234变成1231,将1240变成1231,将1243变成1241。因为在这种表示下,对于所有数字n,其个位上数字2出现次数都是n / 10 + (n % 10 >= 2 ? 1 : 0),即n除以10的商加上余数是否大于等于2。然后我们只需要计算[l, r]对应的数字,再加起来即可得到个位上数字2的总次数。 接着考虑十位上的情况,我们需要将[l, r]的所有数变成以10为十位的形式,如将1234变成1220,将1240变成1240,将1243变成1240。同样地,对于任意数字n,其十位上数字2出现次数可以分为两个部分:低位部分(个位到十位之间)和高位部分(十位以上)。假设当前考虑的位数是十位,对于某个数i,低位部分对2的贡献可以通过 i % 10 来计算,而高位部分可以通过 i / 100 * 10 (如果百位上数字小于2,则为0,否则为10)来计算。然后我们只需要将[l, r]对应的数字加起来即可得到十位上数字2的总次数。 同理,我们可以继续考虑百位、千位等各个位数上数字2出现的情况,每次计算出[l, r]对应位数上数字2的总次数,并求和得到答案即可。 综上所述,我们得到了一个时间复杂度为O(log r)的算法,可以高效地解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pretty Boy Fox

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值