Loading [MathJax]/extensions/tex2jax.js

P3172:「CQOI2015」选数题解

解法

一开始毫无头绪,在看了题解之后豁然开朗(废话,看了题解不都豁然开朗么)。题目中要求我们求出:

\[ 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 \]

搞完了,用杜教筛筛前缀和整除分块即可。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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;
}

Leave a Reply

Your email address will not be published. Required fields are marked *