1. 程式人生 > 實用技巧 >2020 Nowcoder Training - AceSrc and chenjb Contest Problem H. Dividing 數論,整除分塊

2020 Nowcoder Training - AceSrc and chenjb Contest Problem H. Dividing 數論,整除分塊

The following rules define a kind of integer tuple - the Legend Tuple:
(1; k) is always a Legend Tuple, where k is an integer.
if (n; k) is a Legend Tuple, (n + k; k) is also a Legend Tuple.
if (n; k) is a Legend Tuple, (nk; k) is also a Legend Tuple.
We want to know the number of the Legend Tuples (n; k) where 1 n N; 1 k K.

In order to avoid calculations of huge integers, report the answer modulo 109 + 7 instead.
Input
The input contains two integers N and K, 1 N; K 1012.
Output
Output the answer modulo 109 + 7.

很容易想到列舉每個k計算貢獻。

當時畫的草稿:

發現對於每個k。1總是算的,然後就是k,k+1。然後以此為週期。

因此對於一個n,我可以算單個k的貢獻就是 1 + (n - 1) / k 。當然還要加上餘數的部分。

因此總的貢獻就是

當然實現還有很多細節,由於整除分塊寫的不多,很多細節要注意。比如取min,比如溢位,比如先乘還是先除。

int readint() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return
x * f; } ll readll() { ll x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } void Put(ll x) { if (x > 9) Put(x / 10); putchar(x % 10 + '0'); } int main() { ll n, k; n = readll(), k = readll(); if (k == 1ll) { Put(n % MOD); return 0; } if (n == 1ll) { Put(k % MOD); return 0; } ll res = 0; for (ll l = 2, r; l <= k && l <= n - 1; l = r + 1) { assert(l <= n - 1); if (k / l != 0) r = min((n - 1) / ((n - 1) / l), k), r = min(r, n - 1); else r = k; res = (res + (n - 1) / l * (r - l + 1) % MOD) % MOD; } res = res * 2 % MOD; res = (res + (k % MOD) - 1 + MOD) % MOD; for (ll i = 1; i * i <= n; i++) { if (n % i) continue; if (i <= k) res = (res + 1) % MOD; if (n / i <= k && i * i != n) res = (res + 1) % MOD; } res = (res - 1 + MOD) % MOD; res = (res + n) % MOD; Put(res); }