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); }