解法
一开始毫无头绪,在看了题解之后豁然开朗(废话,看了题解不都豁然开朗么)。题目中要求我们求出:
\[ ans = \underbrace{ \sum_{a_1 = L}^R \dots \sum_{a_n = L}^R }_{n \text{ 个}} [\gcd_{i = 1}^n (a_i) = k] \]
考虑先除掉一个\(k\):
\[ ans = \underbrace{ \sum_{a_1 = \frac{L-1}{k}}^\frac{R}{k} \dots \sum_{a_n = \frac{L-1}{k}}^\frac{R}{k} }_{n \text{ 个}} [\gcd_{i = 1}^n (a_i) = 1] \]
考虑把最后那玩意直接反演掉:
\[ ans = \underbrace{ \sum_{a_1 = \frac{L-1}{k}}^\frac{R}{k} \dots \sum_{a_n = \frac{L-1}{k}}^\frac{R}{k} }_{n \text{ 个}} \sum_{d|\gcd_{i = 1}^n (a_i) = 1} \mu(d) \]
提到前面:
\[ \sum_{d = 1}^\frac{R}{k} \mu(d) \underbrace{ \sum_{a_1 = \frac{L-1}{k}}^\frac{R}{k} \dots \sum_{a_n = \frac{L-1}{k}}^\frac{R}{k} }_{n \text{ 个}} 1 \]
后面那一坨都可以整成乘方的形式:
\[ \sum_{d = 1}^\frac{R}{k} \mu(d) (\frac{R}{k} – \frac{L-1}{k})^n \]
搞完了,用杜教筛筛前缀和整除分块即可。
代码
// P3172.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 1e6 + 2000, mod = 1000000007, INF = 0x3f3f3f3f; ll mu[MAX_N], n, k, l, r, prime[MAX_N], tot, inv2; bool vis[MAX_N]; unordered_map<ll, ll> ump; void preprocess() { mu[1] = 1; for (ll i = 2; i < MAX_N; i++) { if (!vis[i]) prime[++tot] = i, mu[i] = -1; for (ll j = 1; j <= tot && prime[j] * i < MAX_N; j++) { vis[prime[j] * i] = true; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } mu[i * prime[j]] = -mu[i]; } } for (int i = 2; i < MAX_N; i++) mu[i] += mu[i - 1]; } ll quick_pow(ll bas, ll tim) { ll ans = 1; while (tim) { if (tim & 1) ans = bas * ans % mod; bas = bas * bas % mod; tim >>= 1; } return ans; } ll sieve(ll num) { if (num < MAX_N) return mu[num]; if (ump.count(num)) return ump[num]; ll ans = 1; for (ll i = 2, gx; i <= num; i = gx + 1) { gx = (num / (num / i)); ans = (ans - (gx - i + 1) % mod * sieve(num / i) % mod + mod) % mod; } return ump[num] = ans; } int main() { scanf("%lld%lld%lld%lld", &n, &k, &l, &r); l = (l - 1) / k, r /= k, inv2 = quick_pow(2, mod - 2); preprocess(); ll ans = 0; for (ll i = 1, gx; i <= r; i = gx + 1) { gx = min(l / i ? l / (l / i) : INF, r / (r / i)); ans = (ans + (sieve(gx) - sieve(i - 1) + mod) % mod * quick_pow(r / i - l / i, n) % mod) % mod; } printf("%lld", (ans + mod) % mod); return 0; }