1. 程式人生 > >[AtCoder arc090F]Number of Digits

[AtCoder arc090F]Number of Digits

long long names namespace coder 兩種 des ref 題解 script

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