【BZOJ】T1101 Zap

题意:

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


题解:

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

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

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

所以原式即可化为

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

优先枚举d的取值,考虑 dgcd(i,j) d ∣ g c d ( i , j ) ,可得 (di)(dj) ( d ∣ i ) ∧ ( d ∣ j )
μ(d) μ ( d ) 被统计进答案,当且仅当 i,j i , j 均为 d d 的整数倍
所以答案为d=1min(N,M)μ(d)×Nd×Md
由于 Nd ⌊ N d ⌋ , Md ⌊ M d ⌋ 取值的阶梯性,我们可以在 O(n) O ( n ) 的时间复杂度下枚举 Nd ⌊ N d ⌋ , Md ⌊ M d ⌋ 的不同取值。
总时间复杂度 O(nn) O ( n n )


#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、付费专栏及课程。

余额充值