LUOGU 2257 YY的GCD - 莫比乌斯反演

Description
神犇YY虐完数论后给kAc出了一题:
给定N, M,1 \leq x \leq N, 1 \leq y \leq Mgcd(x, y)为质数的(x, y)有多少对。
kAc不想做,并把这道题扔给了你。
Input Format

Output Format

Sample Input

2
10 10
100 100

Sample Output

30
2971

Constraints
T = 10^4
对于100%的数据,N,M \leq 10^7
CCYOS
我的第二道莫比乌斯反演题。
本题即计算\sum_{p \in prime}\sum_{i}^{N}\sum_{j}^{M}[gcd(i,j) == p]
g(p)1 \leq x \leq N, 1 \leq y \leq Mgcd(x, y)d(x, y)的个数,g(k) = \sum_{i}^{N}\sum_{j}^{M}[gcd(i,j) = k]代入原式Ans =\sum_{p \in prime}g(p)f(k)1 \leq x \leq N, 1 \leq y \leq Mgcd(x, y)kk的倍数的(x, y)的个数,f(k) = \sum_{k|d}g(d) = \lfloor \frac{N}{k} \rfloor · \lfloor \frac{M}{k} \rfloor莫比乌斯反演的第二种形式,g(k) = \sum_{k|d}\mu(\frac{d}{k})·f(d)代入原式Ans = \sum_{p \in prime}\sum_{p|d}\mu(\frac{d}{p})·f(d)a = \frac{d}{p} Ans = \sum_{p \in prime}\sum_{p|d}\mu(a)·f(ap) Ans = \sum_{p \in prime}\sum_{a = 1}^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)} \mu(a) \lfloor \frac{N}{ap}\rfloor \lfloor \frac{M}{ap}\rfloor = \sum_{p \in prime} \lfloor \frac{N}{ap}\rfloor \lfloor \frac{M}{ap}\rfloor\sum_{a}\mu(a) 再次令T = ap, Ans = \sum_{T} \lfloor \frac{N}{T}\rfloor \lfloor \frac{M}{T}\rfloor·(\sum_{p}\mu(\frac{T}{p}))
code

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

#define mxn 10000005
int T,N,M,cnt;
int prime[mxn],vis[mxn],done[mxn];
long long sum[mxn],mu[mxn];

inline int read(){
    int ret = 0,fl = 1;
    char c = getchar();
    for(;!isdigit(c)&&c != '-';c = getchar())if(c == '-')fl = 0;
    for(;isdigit(c);c = getchar())ret = (ret << 3) + (ret << 1) + c - 48;
    return fl ? ret : -ret;
}

inline void get_mu(int n){
    mu[1] = 1;
    for(int i = 2;i <= n;++i){
        if(!vis[i])prime[++cnt] = i,mu[i] = -1;
        for(int j = 1;j <= cnt&&prime[j] * i<= n;++j){
            vis[i * prime[j]] = 1;
            if(!(i % prime[j]))break;
            else mu[i * prime[j]] = -mu[i];
        }
    }
    for(int j = 1;j <= cnt;++j) 
        for(int i = 1;i * prime[j] <= n;++i)
            done[i * prime[j]] += mu[i];//储存处理完后的mu[i]
    for(int i = 1;i <= n;++i)
        sum[i] = 1ll * (sum[i - 1] + done[i]);
}

int main(){
    T = read();
    get_mu(10000000);
    for(int i = 1;i <= T;++i){
        N = read();M = read();  
        int limit = min(N,M);
        long long ans = 0;
        for(int l = 1,r;l <= limit;l = r + 1){
                r = min(N/(N/l),M/(M/l));
                ans += 1ll * (N/l) * (M/l) * (sum[r] - sum[l - 1]);//long long
            }
        printf("%lld\n",ans);
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容