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 \times gcd(x,y)$

$\sum\limits_x\sum\limits_y \sum\limits_{g=gcd(x,y)} g\times \mu(g)^2$

$\sum\limits_g g\times \mu(g)^2 \sum\limits_{x=1}^{n/g} \sum\limits_{y=1}^{n/g} [gcd(x,y)==1]$

$t=d \times g$

$\sum\limits_g g\times \mu(g)^2 \sum\limits_t \mu(t/g)\times (n/t)\times (m/t)$

对于每一个t预处理
$\sum\limits_g g\times \mu(g)^2 \sum\limits_t \mu(t/g)$
$O(nln(n))$


$ (n/t)\times (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\n",A);
    }
    return 0;
}
View Code

 

posted @ 2020-02-12 21:00  liankewei123456  阅读(156)  评论(0编辑  收藏  举报