【BZOJ】T1101 Zap

本文详细解析了求解给定范围内所有i和j的组合中,使得gcd(i,j)==d的个数的问题。通过数学推导,利用莫比乌斯函数的性质简化了问题,并给出了具体的实现代码。
题意:

k次询问,每次询问ni=1mj=1gcd(i,j)==d∑i=1n∑j=1mgcd(i,j)==d,即gcd(i,j)结果为d的个数。
k,n,m≤5e5。


题解:

原式显然可以化简为Ni=1Mj=1gcd(i,j)==1∑i=1N∑j=1Mgcd(i,j)==1,其中N=nd,M=mdN=⌊nd⌋,M=⌊md⌋
由于莫比乌斯函数有一个性质:

dnμ(d)={1,n=1.0,n1.∑d∣nμ(d)={0,n≠1.1,n=1.

n=1时,显然原式值为1;
n≠1时,设d=k1piaid=∏1kpiai,p为质数,a≠0,讨论每个d对答案的贡献。
- ai2∃ai≥2,d对答案的贡献=0;
- ai=1∀ai=1,d对答案的贡献=(k0)(k1)+(k2)(k3)+(k0)−(k1)+(k2)−(k3)+…
根据二项式定理,当d不为1时对答案的贡献均为0,所以性质得证。

所以原式即可化为

i=1Nj=1Mdgcd(i,j)μ(d)∑i=1N∑j=1M∑d∣gcd(i,j)μ(d)

优先枚举d的取值,考虑dgcd(i,j)d∣gcd(i,j),可得(di)(dj)(d∣i)∧(d∣j)
μ(d)μ(d)被统计进答案,当且仅当i,ji,j均为dd的整数倍
所以答案为d=1min(N,M)μ(d)×Nd×Md
由于Nd⌊Nd⌋,Md⌊Md⌋取值的阶梯性,我们可以在O(n)O(n)的时间复杂度下枚举Nd⌊Nd⌋,Md⌊Md⌋的不同取值。
总时间复杂度O(nn)O(nn)
#include<cstdio>
#include<algorithm>
#define N 55000
#define mx 50000
using namespace std;
int mobius[N],prime[N],flag[N],tot=0,sum[N];
void sol(){
    mobius[1]=1;
    for(int i=2;i<=mx;i++){
        if(!flag[i]){prime[tot++]=i;mobius[i]=-1;}
        for(int j=0;j<tot;j++){
            if(prime[j]*i>50000)break;
            flag[prime[j]*i]=true;
            if(i%prime[j]==0){mobius[prime[j]*i]=0;break;}
            else mobius[prime[j]*i]=-mobius[i];
        }
    }
    for(int i=1;i<=mx;i++)sum[i]=mobius[i]+sum[i-1];
    return;
}
int main(){
    int n;
    scanf("%d",&n);
    sol();
    while(n--){
        int n,m,d;
        scanf("%d%d%d",&n,&m,&d);
        n/=d,m/=d;
        //sigma(mobius(d)*(n/d)*(m/d))
        int ans=0,t;
        for(int i=1;(n/i)&&(m/i);i=t+1){
            t=min(n/(n/i),m/(m/i));
            ans+=(sum[t]-sum[i-1])*(n/i)*(m/i);
        }
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值