「Bzoj 3930」「CQOI2015」选数(莫比乌斯反演 + GCD性质 / 杜教筛)

BZOJ 3930
题意:给定$n,K,H,L$,求

Markdown

这个形式和在$[1,n],[1,m]$中的$gcd$类似,我们从$N=2$开始考虑。
显然
$$
f(k)=\sum_{d=1}^{\lfloor \frac nk \rfloor} \mu(d) \left \lfloor \frac n{kd} \right \rfloor^2
$$
扩展到高维也类似,所以可以得到
$$
f(k)= \sum_{d=1}^{\lfloor \frac Hk \rfloor} \mu(d) \left (\left \lfloor \frac H{kd} \right \rfloor - \left \lfloor \frac {L - 1}{kd} \right \rfloor \right )^n
$$

然而$\lfloor \frac Hk \rfloor$是$O(H)$级的,不能满足。

引理:

当所有数不全部相同时,$\gcd\left ( i_1, i_2, \dots, i_N \right ) \leq \max\left ( i_1, i_2, \dots, i_N \right ) - \min\left ( i_1, i_2, \dots, i_N \right )$

证明:设$d = \gcd\left ( i_1, i_2, \dots, i_N \right ), a = \min\left ( i_1, i_2, \dots, i_N \right ), b = \max\left ( i_1, i_2, \dots, i_N \right )$
显然$a = k_1d (k_1 \in \mathbb{Z}^+), b = k_2d (k_2 \in \mathbb{Z}^+, k_2 > k_1)$, 所以$b - a \geq d$,证毕。

所以$[H, L]$中的一个不全部相同的序列的$\gcd$不会超过$H - L$个,只用处理不全部相同的序列,所以可以得到

$$
f(k)= \sum_{d=1}^{\lfloor \frac Hk \rfloor - \lfloor \frac {L-1}k \rfloor} \mu(d) \left( \left (\left \lfloor \frac H{kd} \right \rfloor - \left \lfloor \frac {L - 1}{kd} \right \rfloor \right )^n - \left (\left \lfloor \frac H{kd} \right \rfloor - \left \lfloor \frac {L - 1}{kd} \right \rfloor \right )\right)+[L \leq k \leq H]
$$

注意需要加上$[L \leq k \leq H]$,因为这样就可以选$n$个$k$。

本题也可以直接杜教筛筛出$\mu(d)$的前缀和,但是我并不会……等学了杜教筛再来填坑吧。

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<string>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;

namespace flyinthesky {

    const LL MO = 1000000007ll, MAXN = 100000 + 5;

    LL n, k, L, H;
    LL vis[MAXN], mu[MAXN], pri[MAXN], tot;

    LL ksm(LL a, LL b) {
        LL bs = a, ans = 1;
        while (b) {
            if (b & 1) ans = (ans * bs) % MO;
            bs = (bs * bs) % MO;
            b >>= 1;
        }
        return ans;
    }

    void clean() {
        ms(vis, 0), ms(mu, 0), ms(pri, 0), tot = 0;
    }
    int solve() {

        clean();
        cin >> n >> k >> L >> H;

        mu[1] = 1;
        for (LL i = 2; i <= 100000; ++i) {
            if (!vis[i]) pri[++tot] = i, mu[i] = -1;
            for (LL j = 1; j <= tot && pri[j] * i <= 100000; ++j) {
                vis[pri[j] * i] = 1;
                if (i % pri[j] == 0) {
                    mu[pri[j] * i] = 0;
                    break ;
                } else mu[pri[j] * i] = mu[i] * mu[pri[j]];
            }
        }
        for (LL i = 2; i <= 100000; ++i) mu[i] += mu[i - 1];

        LL ans = 0;
        if (L <= k && k <= H) ++ans;

        LL l = 1, len = H - L;
        H /= k, L = (L - 1) / k;
        while (l <= len && l <= H) {
            LL r;
            if (L / l == 0) r = H / (H / l); else r = min(H / (H / l), L / (L / l));
            LL tmp = ( ksm( (H / l - L / l + MO) % MO, n ) - (H / l - L / l + MO) % MO + MO ) % MO * ( ( mu[r] - mu[l - 1] + MO ) % MO ) % MO;
            ans = (ans + tmp) % MO;
            l = r + 1;
        }

        printf("%lld\n", ans);

        return 0;
    }
}
int main() {
    flyinthesky::solve();
    return 0;
}
/*
2 3 2 4
3 2 2 4
*/
------ 本文结束 ------