码迷,mamicode.com
首页 > 其他好文 > 详细

[ZJOI 2010]count 数字计数

时间:2018-02-28 14:41:34      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:多少   www   php   using   rip   链接   clu   +=   gpo   

Description

题库链接

问你 \([l,r]\) 区间内所有整数中各个数码出现了多少次。

\(1\leq a\leq b\leq 10^{12}\)

Solution

数位 \(DP\)

定义一个函数 \(cal(i)\) 为求 \([1,i)\) 中所有整数各个数码的和。显然答案就是 \(cal(r+1)-cal(l)\)

考虑如何求 \(cal(x)\)

先考虑数的位数小于 \(x\) 的情况。假设 \(x\) 的总位数为 \(tot\) 。我们可以从 \(1\sim tol-1\) 来枚举最高位。对于每次枚举的最高位 \(i\) ,显然最高位上的每个数都会计算 \(10^{i-1}\) 次, \(0\) 除外。再考虑以其为最高位开头。之后的所有数码产生的新贡献为 \(9(i-1)\cdot 10^{i-2}\) 其中 \(9\) 表示最高位有 \([1,9]\)\(9\) 个数; \(i-1\) 表示之后共有 \(i-1\) 位。 \(10^{i-2}\) 指的是每一位会产生贡献(推推式子可以证明后面的每一位的数码出现频率是相同的)。

最高位等于 \(tot\) 的情况和上面是类似的,假设 \(x_i\)\(x\) 的第 \(i\) 位上的数字。显然对于小于 \(x_i\) 的所有数码(包括除最高位外的 \(0\) ),都会计算 \(10^{i-1}\) 次。而 \(x_i\) 只会计算 \(last\) 次,其中 \(last\)\(i\) 位之后的数字;之后的所有数码产生的新贡献和上面类似,详可见代码。

Code

//It is made by Awson on 2018.2.28
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
void read(LL &x) {
    char ch; bool flag = 0;
    for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    x *= 1-2*flag;
}
void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }

LL x, y, cnt[15];

void cal(LL x) {
    LL a[20], tot = 0, mi = 1, last = 0; while (x) a[++tot] = x%10, x /= 10;
    for (int i = 1; i < tot; i++) {
    for (int d = 1; d < 10; d++) cnt[d] += mi;
    for (int d = 0; d < 10; d++) cnt[d] += mi*9/10*(i-1); mi *= 10;
    }
    mi = 1;
    for (int i = 1; i <= tot; i++) {
    cnt[a[i]] += last; int begin = (i == tot);
    for (int d = begin; d < a[i]; d++) cnt[d] += mi;
    if (a[i]) for (int d = 0; d < 10; d++) cnt[d] += mi*(a[i]-begin)/10*(i-1);
    last += mi*a[i], mi *= 10;
    }
}
void work() {
    read(x), read(y);
    cal(x); for (int i = 0; i < 10; i++) cnt[i] = -cnt[i];
    cal(y+1); for (int i = 0; i < 9; i++) write(cnt[i]), putchar(' '); writeln(cnt[9]);
}
int main() {
    work(); return 0;
}

[ZJOI 2010]count 数字计数

标签:多少   www   php   using   rip   链接   clu   +=   gpo   

原文地址:https://www.cnblogs.com/NaVi-Awson/p/8483411.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!