洛谷P2257 YY的GCD 莫比乌斯反演

原题链接
差不多算自己推出来的第一道题QwQ

题目大意

\(T\)组询问,每次问你\(1\leqslant x\leqslant N\)\(1\leqslant y\leqslant M\)中有多少\((x,y)\)满足\(gcd(x,y)\in \mathbb{P}\)

数据范围

\(T=10000\)\(1\leqslant N,M\leqslant 10000000\)
显然,暴力不可做。
这种公约数计数的题貌似大多都是用莫比乌斯反演做的?套路啊,套路。
首先,我们先很套路地设一个函数\(f(n)\)(方括号的意思是,若里面的表达式为真,则值为\(1\),否则为\(0\)),

\(f(n)=\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{M}[gcd(i,j)==n]\)

然后,我们再很套路的设一个函数 \(F(n)\),并定义
\(F(n)=\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{M}[n|gcd(i,j)]\)

由乘法原理,易得 \(F(n)=\left \lfloor \frac{N}{n} \right \rfloor \left \lfloor \frac{M}{n} \right \rfloor\)。然后,由 \(f(n)\)\(F(n)\)的定义,显然有 \(F(n)=\sum\limits_{n|d}f(d)\)
反演一波,得到
\(f(n)=\sum\limits_{n|d}\mu (\frac{d}{n})F(d)\)

接下来就是简(ma)单(fan)的化简环节了,令答案为 \(A\),可得
\(A=\sum\limits_{p\in\mathbb{P}}f(p)=\sum\limits_{p\in\mathbb{P}}\sum\limits_{p|d}\mu (\frac{d}{p})F(d)\)

\(t=\frac{d}{p}\),代入并继续化简
\(A=\sum\limits_{p\in\mathbb{P}}\sum\limits_{t=1}^{min\{\left \lfloor \frac{N}{p} \right \rfloor,\left \lfloor \frac{M}{p} \right \rfloor\}}\mu (t)F(pt)=\sum\limits_{p\in\mathbb{P}}\sum\limits_{t=1}^{min\{\left \lfloor \frac{N}{p} \right \rfloor,\left \lfloor \frac{M}{p} \right \rfloor\}}\mu (t)\left \lfloor \frac{N}{pt} \right \rfloor \left \lfloor \frac{M}{pt} \right \rfloor\)

\(T=pt\),代入
\(A=\sum\limits_{p\in\mathbb{P}}\sum\limits_{p|T}^{min\{N,M\}}\mu (\frac{T}{p})\left \lfloor \frac{N}{T} \right \rfloor \left \lfloor \frac{M}{T} \right \rfloor\)

交换和号,推出
\(A=\sum\limits_{T=1}^{min\{N,M\}}\sum\limits_{p\in\mathbb{P},p|T}\mu (\frac{T}{p})\left \lfloor \frac{N}{T} \right \rfloor \left \lfloor \frac{M}{T} \right \rfloor\)

\(\left \lfloor \frac{N}{T} \right \rfloor \left \lfloor \frac{M}{T} \right \rfloor\)提到前面,化简到最终式子
\(A=\sum\limits_{T=1}^{min\{N,M\}}\left \lfloor \frac{N}{T} \right \rfloor \left \lfloor \frac{M}{T} \right \rfloor\sum\limits_{p\in\mathbb{P},p|T}\mu (\frac{T}{p})\)

终于写完了,巨长的 \(L^AT_EX\)
观察式子,后面的一部分可以用前缀和搞定,前面的就是整除分块的拿手好戏了。注意,因为 \(N,M\)的值可能不同,所以每次更新 \(r\)的值时,要取 \(r=min\{\frac{N}{\left \lfloor \frac{N}{l} \right \rfloor},\frac{M}{\left \lfloor \frac{M}{l} \right \rfloor}\}\)
其他的看代码吧:

#include <bits/stdc++.h>

using namespace std;

#define N 10000000

int T, n, m, cnt, ans, mu[N+5], sum[N+5], vis[N+5], prime[N+5];

void get_mu(int lim) {
    mu[1] = 1, vis[1] = 1;
    for(int i = 2; i <= lim; ++i) { //筛素数时计算μ函数
        if(!vis[i]) prime[++cnt] = i, mu[i] = -1;
        for(int j = 1; j <= cnt && i*prime[j] <= lim; ++j) {
            vis[i*prime[j]] = 1;
            if(i%prime[j] == 0) break;
            else mu[i*prime[j]] = -mu[i];
        }
    }
    for(int j = 1; j <= cnt; ++j)
        for(int i = 1; i*prime[j] <= lim; ++i)
            sum[i*prime[j]] += mu[i];
    for(int i = 1; i <= lim; ++i) sum[i] += sum[i-1];//计算前缀和
}

void init() {
    cin >> T;
    get_mu(N);
}

int main() {
    init();
    while(T--) {
        cin >> n >> m;
        long long ans = 0; //要开long long
        int t = min(n, m);
        for(int l = 1, r; l <= t; l = r+1) {
            r = min(n/(n/l), m/(m/l));
            ans += 1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]); //就是最后推出的那个式子
        }
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/dummyummy/p/9640599.html