【每日一题】数码

数码

https://ac.nowcoder.com/acm/problem/13221

首先,对于求区间 [l, r] 的问题,可以转换成求 [1, r] 的问题。答案为 [1, r] 的结果减去 [1, l - 1] 的结果。
然后,需要分别统计最高位数字不同的约数的出现的次数,我们可以转变思路,枚举约数,统计每个约数在区间中出现的次数。
假设这道题没有区分最高位,只是求约数个数,那就是一道经典的数论分块题目,求 [l, n] 中每个数约数的个数和,枚举约数,问题转换成求 ,直接计算的复杂度是
可以通过打表观察到, 的间隔会越来越大。于是我们就可以通过计算每个 的区间 [l, r] 的长度,快速计算每段区间的和,因为 的取值大约只有 个,复杂度为 ,具体复杂度证明请百度。
但是现在需要对每种数码进行区分,只需要在每次分块过程中将最高位不同的数分开统计就行了。
求一个区间中最高位为 x 出现的次数,这个问题应该是有很多做法。因为最高位数相同且位数相同的数字是连续的,所以对于每一种数码,可以枚举位数来计算出区间中这个数码出现的次数。

#include <bits/stdc++.h>
using namespace std;
static auto faster_iostream = []() { ios::sync_with_stdio(0); cin.tie(0); return 0; }();
typedef long long ll;

ll ans[10];

void solve(int n, int op) {
  for (ll l = 1, r; l <= n; l = r) { // [l, r)
    r = n / (n / l) + 1;
    for (int i = 1; i <= 9; i++) {
      int len = 0;
      for (ll L = i, R = i + 1; L < r; L *= 10, R *= 10)
        len += max(0ll, min(r, R) - max(l, L));
      ans[i] += op * len * (n / l);
    }
  }
}

int main() {
  int a, b;
  cin >> a >> b;
  solve(b, 1);
  solve(a-1, -1);
  for (int i = 1; i <= 9; i++) {
    cout << ans[i] << '\n';
  }
}
全部评论

相关推荐

03-20 18:39
已编辑
电子科技大学 C++
点赞 评论 收藏
分享
评论
5
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务