BZOJ 2820 - YY的GCD(莫比乌斯反演)

题目链接 https://cn.vjudge.net/problem/HYSBZ-2820

【题目描述】
神犇YY虐完数论后给傻×kAc出了一题
给定N,M,求1<=x<=N,1<=y<=Mgcd(x,y)为质数的(x,y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入T=10000N,M<=10000000

【输入格式】
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M

【输出格式】
T行,每行一个整数表示第i组数据的结果

【样例输入】
2
10 10
100 100

【样例输出】
30
2791

【思路】
贴一篇大佬的题解,太强了 BZOJ2820
本菜鸡差不多照猫画虎抄了一遍代码

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

const int maxn=10000005;

bool vis[maxn];
int prim[maxn];
int mu[maxn];
ll g[maxn],sum[maxn];
int cnt;

void get_mu(int n){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            prim[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cnt && prim[j]*i<=n;j++){
            vis[prim[j]*i]=1;
            if(i%prim[j]==0) break;
            else mu[i*prim[j]]=-mu[i];
        }
    }

    for(int j=1;j<=cnt;++j){
        for(int i=1;i*prim[j]<=n;++i){
            g[i*prim[j]]+=mu[i];
        }
    }
    for(int i=1;i<=n;++i) sum[i]=sum[i-1]+g[i];
}

int main(){
    get_mu(maxn-1);
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        ll ans=0;
        for(int L=1,R;L<=n;L=R+1){
            R=min(n/(n/L),m/(m/L));
            ans+=(sum[R]-sum[L-1])*(ll)(n/L)*(ll)(m/L);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-08-30 17:31  不想吃WA的咸鱼  阅读(101)  评论(0编辑  收藏  举报