P3455 [POI2007]ZAP-Queries

【题意】

给定a,b,d,求满足$1 \leq x \leq a,1 \leq y \leq b,gcd(a,b)=1$的有序对$(x,y)$的数对数

【分析】

推式子,用莫比乌斯反演的嵌入式形式$[n=1]=\sum_{d|n}\mu(d)$

首先看到$gcd(a,b)=d$这个等于d不好求,我们把$x,y$设为$id,jd$

此时$ans=\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)==1]$

然后用莫比乌斯反演

$ans=\sum_{d=1}^{\frac{n}{d}}\mu{(d)}\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}1$

后面两个用一下数论分块即可

【代码】

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define fi first
#define se second
#define lson now<<1
#define rson now<<1|1
typedef long long ll;
const int maxn=5e4+5;
int n,a,b,x;
int np[maxn],cnt,mu[maxn],p[maxn];
int sum[maxn];
void init()
{
    mu[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(!np[i])
        {
            mu[i]=-1;
            p[++cnt]=i;
        }
        for(int j=1;p[j]*i<maxn;j++)
        {
            np[i*p[j]]=1;
            if(i%p[j]==0)
            {
                mu[i*p[j]]=0;
                break;
            }
            else mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<maxn;i++) sum[i]=sum[i-1]+mu[i];
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d",&n);
    init();
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a,&b,&x);
        ll ans=0;
        a/=x; b/=x;
        for(int i=1,j;i<=min(a,b);i=j+1)
        {
            j=min(a/(a/i),b/(b/i));
            ans+=1LL*(sum[j]-sum[i-1])*(a/i)*(b/i);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2021-05-31 13:40  andyc_03  阅读(38)  评论(0编辑  收藏  举报