牛客 数码

牛客 数码

题意

对于所有满足属于区间 [ l , r ] [l,r] [l,r] n u m num num,把 n u m num num 所有因子写下来,对于写下来的数,只保留最高位数,求 1 − 9 1-9 19 每个数出现的次数。

题解
  • 为了简化问题,可以求从 [ 1 , l − 1 ] [1,l-1] [1,l1] [ 1 , r ] [1,r] [1,r] 的情况,然后做差得到 [ l , r ] [l,r] [l,r] 的答案,这样可以不用管左边界,接下来就是要求 [ 1 , n ] [1,n] [1,n] 的答案即可;
  • 因子都是成对出现的,所以把 n u m num num 写成 n u m = x ⋅ y ( x ≤ y ) num=x\cdot y(x\le y) num=xy(xy) 的形式;
  • 枚举 x x x 的范围 [ 1 , n ] [1,\sqrt n] [1,n ] ,先特判 x = y x=y x=y 的情况,也就是有一个因子 x x x ,然后对应的 y y y 的取值范围是 [ x + 1 , ⌊ n x ⌋ ] [x+1,\left \lfloor \frac{n}{x} \right \rfloor ] [x+1,xn] ,那么 x x x 因子做 ⌊ n x ⌋ − ( x + 1 ) + 1 \left \lfloor \frac{n}{x} \right \rfloor-(x+1)+1 xn(x+1)+1 次贡献,每一个 y y y 做一次贡献;
  • 计算 y y y 所作的贡献也用前缀的方法忽略左边界,也就是 [ 1 , ⌊ n x ⌋ ] [1,\left \lfloor \frac{n}{x} \right \rfloor ] [1,xn] 的每个数做一次贡献减掉 [ 1 , x ] [1,x] [1,x] 的每一个数做一次贡献。
代码
#pragma region
//#pragma optimize("Ofast")
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 15;
ll getnum(ll x) {
    while (x > 9) x /= 10;
    return x;
}
void cul(ll y, ll val, ll a[]) {
    ll now = 1, cnt = 1;
    while (now * 10 <= y + 1) {
        rep(i, 1, 9) a[i] += cnt * val;
        now *= 10, cnt *= 10;
    }
    ll tmp = now;
    rep(i, 1, 9) {
        if (now + tmp <= y + 1) {
            a[i] += cnt * val;
            now += tmp;
        } else {
            a[i] += (y - now + 1) * val;
            break;
        }
    }
}
void solve(ll n, ll a[]) {
    for (ll x = 1; x * x <= n; ++x) {
        a[getnum(x)] += 1 + (n / x - x - 1 + 1);
        cul(n / x, 1, a), cul(x + 1 - 1, -1, a);
    }
}
ll a[maxn], b[maxn];
int main() {
    ll l, r;
    scanf("%d%d", &l, &r);
    solve(l - 1, a), solve(r, b);
    rep(i, 1, 9) printf("%lld\n", b[i] - a[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值