dtoj1836老逗的gcd(gcd)



对于100%的数据, $T leq 10^4, 1 leq n leq 10^7, 1 leq m leq 10^7$


Sol.

$f(x,y)=mu(gcd(x,y))^2 imes gcd(x,y)$

$sumlimits_xsumlimits_y sumlimits_{g=gcd(x,y)} g imes mu(g)^2$

$sumlimits_g g imes mu(g)^2 sumlimits_{x=1}^{n/g} sumlimits_{y=1}^{n/g} [gcd(x,y)==1]$

$t=d imes g$

$sumlimits_g g imes mu(g)^2 sumlimits_t mu(t/g) imes (n/t) imes (m/t)$

对于每一个t预处理
$sumlimits_g g imes mu(g)^2 sumlimits_t mu(t/g)$
$O(nln(n))$


$ (n/t) imes (m/t)$整数分块

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 10000007
#define ll long long
using namespace std;
int T,n,m,pri[maxn],tot,flag[maxn],mu[maxn];
ll s[maxn]; 
void init(){
    n=10000000;
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!flag[i]){mu[i]=-1;pri[++tot]=i;}
        for(int j=1;j<=tot&&i*pri[j]<=n;j++){
            flag[i*pri[j]]=1;
            if(i%pri[j]==0){
                mu[i*pri[j]]=0;break;
            }
            mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)if(mu[i])
    for(int j=i;j<=n;j+=i)s[j]+=1LL*mu[j/i]*i;
    for(int i=1;i<=n;i++)s[i]+=s[i-1];
}
ll get(int n,int m){
    ll Sum=0;
    for(int l=1,r;l<=n;l=r+1){
        r=min(n/(n/l),m/(m/l));
        Sum+=1LL*(s[r]-s[l-1])*(n/l)*(m/l);
    }
    return Sum;
}
int main(){
    init();
    cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        if(n>m)swap(n,m);
        ll A=get(n,m);/*
        for(int d=2;d*d<=n;d++){
            A+=1LL*mu[d]*d*d*get(n/d/d,m/d/d);
        }*/
        printf("%lld
",A);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liankewei/p/12300871.html