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

[AtCoder arc090F]Number of Digits

时间:2018-02-03 16:07:40      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:ber   read   链接   pow   tps   +=   coder   ase   long   

Description

题库链接

\(d\) 在十进制下的位数为 \(f(d)\) 。给出询问 \(S\) ,求有多少对 \((l,r)\) 使得 \[\sum_{i=l}^r f(i)=S\]

\(1\leq S\leq 10^8\)

Solution

颓了题解...

注意到当数字越大时 \(f(r)-f(l)\) 会越小。

分两种情况讨论:

  1. \(f(l)\leq 7\) ,这时可以用尺取法来做,可以发现它的右界为 \(10^7+\frac{10^8}{8}=25500000\)

  2. \(f(l)\geq 8\) ,我们依旧可以分两种情况来考虑:

    1. \(f(r)-f(l)=0\) ,此时显然选的数都是位数相同的,我们可以统计这种位数的个数 \(sum\) ,该种情况的答案 \(sum-f(l)+1\)

    2. \(f(r)-f(l)=1\) 。假设取的数个数为 \(t\) ,即 \(r-l+1=t\) ,取长度为 \(f(l)\) 的个数为 \(x\) ,长度为 \(f(r)\) 的个数为 \(y\)\[\begin{cases}x+y=t\\x\cdot f(l)+y\cdot f(r)=S\end{cases}\]
      那么 \(f(l)\cdot t+y=S\) 我们可以枚举 \(t\) ,容易发现 \(\begin{cases}y=S~mod~t\\x=t-S~mod~t\end{cases}\) ,即对于每个 \(t\) ,都可以解出唯一解。值得注意的是这方面的解会和上面的解重复,即当 \(f(l)\mid S\) 这里会计算一次。

综上可以分情况处理。

Code

//It is made by Awson on 2018.2.3
#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;
const int l1 = 10000000;
const int l2 = 25500000;
const int yzh = 1e9+7;
void read(int &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(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }

int s, f[l2+5];

int quick_pow(int a, int b) {
    int ans = 1;
    while (b) {
    if (b&1) ans = 1ll*ans*a%yzh;
    a = 1ll*a*a%yzh, b >>= 1;
    }
    return ans;
}
int count1(int n) {
    int ans = 0, r = 0, cnt = 0;
    for (int i = 1; i < l1; i++) {
    cnt -= f[i-1];
    while (cnt+f[r+1] <= s && r < l2) cnt += f[++r];
    if (cnt == s) ++ans;
    if (r == l2) break;
    }
    return ans;
}
int count2(int n) {
    int lim = n/8, ans = lim;
    for (int t = 1; t <= lim; t++)
    if (n%t == 0) {
        int len = n/t;
        (ans += (1ll*quick_pow(10, len-1)*9%yzh-t)%yzh) %= yzh;
    }
    return ans;
}
void work() {
    for (int i = 1, r = 10, cnt = 1; i < l1; i++, i = r, r = r*10, cnt++)
    for (int j = i; j < r; j++) f[j] = cnt;
    for (int i = l1; i <= l2; i++) f[i] = 8;
    read(s);
    writeln(((count1(s)+count2(s))%yzh+yzh)%yzh);
}
int main() {
    work();
    return 0;
}

[AtCoder arc090F]Number of Digits

标签:ber   read   链接   pow   tps   +=   coder   ase   long   

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

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