luogu-P2257-YY的gcd

题意

直接看题面吧 luogu P2257

思路

莫比乌斯反演(虽然本质上是容斥,在这里推公式更好做,但有时候容斥更好想)

参考自JustinRochester的blog

\[\begin{aligned} (p \in &\ prime)\\ Ans &=\sum _p \sum_{i=1}^N \sum_{i=1}^M [gcd(i,j)==p] \\ &= \sum _p \sum_{i=1}^{\lfloor \frac{N}{p}\rfloor} \sum_{j=1}^{\lfloor \frac{M}{p}\rfloor} [gcd(i,j)=1] \\ &= \sum _p \sum _{k=1} ^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)} \mu(k) \cdot \lfloor \frac{\lfloor \frac{N}{p}\rfloor}{k}\rfloor \cdot \lfloor \frac{\lfloor \frac{M}{p}\rfloor}{k}\rfloor \\ &= \sum _p \sum _{k=1} ^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)} \mu(k) \cdot \lfloor \frac{N}{p\cdot k}\rfloor \cdot \lfloor \frac{M}{p\cdot k}\rfloor \\ (&T=k\cdot p) \\ &= \sum _p \sum _{T=1} ^{min(N,M)} [p|T]\cdot \mu(\frac{T}{p}) \cdot \lfloor \frac{N}{T}\rfloor \cdot \lfloor \frac{M}{T}\rfloor \\ &=\sum _{T=1} ^{min(N,M)} \lfloor \frac{N}{T}\rfloor \cdot \lfloor \frac{M}{T}\rfloor \sum _p [p|T]\cdot \mu(\frac{T}{p}) \\ &=\sum _{T=1} ^{min(N,M)} \lfloor \frac{N}{T}\rfloor \cdot \lfloor \frac{M}{T}\rfloor \sum _{p\in Prime,p|T} \mu(\frac{T}{p}) \end{aligned} \]

考虑预处理\(\sum _{p\in Prime,p|T} \mu(\frac{T}{p})\),然后就能\(O(max(N,M))\)算,再数论分块就能达到\(O(\sqrt{max(N,M)})\)

\(F(T)=\sum _{p\in Prime,p|T} \mu(\frac{T}{p})\),由于\(10^7\)内质数个数约为7e5个,我们可以枚举质数在\(O(nlog\ n)\)跑出每个质数对不同F(T)的贡献并叠加

代码

代码中由于个人习惯问题\(\mu(1) = -1\),其他都一样

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

const int MX = 1e7+6;

int mob[MX] = {0};
bool notP[MX] = {false};
int prms[MX];
int prm=0;
int T[MX] = {0};
int sumT[MX];

void get_mob() { // pre process
    mob[1] = -1; // <-- you can make it 1, and make mob[prime]=-1
    for(int i=2;i<MX;++i) {
        if(!notP[i]) {
            prms[prm] = i; // get prime
            ++prm;
            mob[i] = 1; // get mob
        }
        for(int j=0;j<prm;++j) {
            if(i*prms[j]>=MX) break;

            mob[i*prms[j]] = -mob[i];
            notP[i*prms[j]] = true;

            if(i%prms[j]==0) {
                mob[i*prms[j]] = 0;
                break;
            }
        }
    }
    for(int i=0;i<prm;++i) { // get F(T)
        for(int j=1;j*prms[i]<MX;++j) {
            T[j*prms[i]] += mob[j];
        }
    }
    sumT[0] = T[0];
    for(int i=1;i<MX;++i) {
        sumT[i] = sumT[i-1] + T[i];
    }
}

int main(int argc, char const *argv[])
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);

    get_mob();
    int t;
    cin >> t;
    while(t--) {
        i64 N,M;
        cin >> N >> M;
        i64 ans=0;
        if(N>M) swap(N,M);
        for(i64 l=1,r;l<=N;l=r+1) {
            r = min(N/(N/l),M/(M/l));
            r = min(r,N);
            ans += (N/l) * (M/l) * (sumT[r]-sumT[l-1]);
        }
        cout << -ans << '\n';
    }
    return 0;
}
posted @ 2021-11-15 17:00  LacLic  阅读(28)  评论(0编辑  收藏  举报