CIA3 Sometimes Naive(莫比乌斯反演+积性函数前缀和)

33 篇文章 0 订阅
16 篇文章 0 订阅

题意:求 x=1ny=1mφ(gcd(x,y))
根据各种老套路化简得 i=1nn/im/id|iφ(i/d)μ(d)
因此我们只需要处理出f[i]= d|iφ(i/d)μ(d) ,这个函数的前缀和就可以了。暴力跳倍数更新是过不了所有数据的。我们观察这个函数有什么性质,它是个积性函数!积性函数我们可以通过线性素数筛线性的算出!然后,就可以了。
tips:f数组要开ll哟~

#include <bits/stdc++.h>
#define ll long long
#define N 10000010
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int tst,n,m,fai[N],prime[N/10],tot=0,mu[N],mnfac[N];
ll f[N];
bool notprime[N];
void Mobius(){
    notprime[1]=1;mu[1]=1;fai[1]=1;f[1]=1;
    for(int i=2;i<=1e7;++i){
        if(!notprime[i]){
            prime[++tot]=i;mu[i]=-1;fai[i]=i-1;
            f[i]=fai[i]-1;mnfac[i]=i;
        }for(int j=1;prime[j]*i<=1e7;++j){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;fai[i*prime[j]]=fai[i]*prime[j];
                mnfac[i*prime[j]]=mnfac[i]*prime[j];
                if(mnfac[i*prime[j]]==i*prime[j]){
                    f[i*prime[j]]=fai[i*prime[j]]-fai[i];
                }else f[i*prime[j]]=f[i/mnfac[i]]*f[mnfac[i*prime[j]]];
                break;
            }mu[i*prime[j]]=-mu[i];fai[i*prime[j]]=fai[i]*fai[prime[j]];
            mnfac[i*prime[j]]=prime[j];f[i*prime[j]]=f[i]*f[prime[j]];
        }
    }for(int i=1;i<=1e7;++i) f[i]+=f[i-1];
}
int main(){
 //   freopen("a.in","r",stdin);
    tst=read();Mobius();
    while(tst--){
        n=read();m=read();if(n>m) swap(n,m);ll ans=0;int last=0;
        for(int i=1;i<=n;i=last+1){
            last=min(n/(n/i),m/(m/i));
            ans+=(ll)(f[last]-f[i-1])*(n/i)*(m/i);
        }        
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值