[bzoj2301] [HAOI2011]Problem b

题意:t组数据,求$aleqslant x leqslant b , cleqslant yleqslant d , gcd(x,y)=k$的个数 $t,a,b,c,d,k leqslant 50000$

题解:我们可以同时除以k,然后容斥原理,题意转换为求$1leqslant x leqslant a1 , 1leqslant yleqslant b1 , gcd(x,y)=1$的个数。

根据$sum_{d|n}mu(d)=[n=1]$,所以转换为求$sum_{1}^{a1}sum_{1}^{b1}sum_{d|a1,d|b1}mu(d)$

从d看待这个式子,得到$sum_{d=1}^{min(a1,b1)}mu(d)*lfloor frac{a1}{d} floor*lfloor frac{b1}{d} floor$

然后$lfloor frac{a1}{d} floor$只有$sqrt(a1)$种取值. 预处理$mu(i)$的前缀和

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#define MAXN 50000
#define ll long long
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 f[MAXN+5],s[MAXN/5],num=0;
bool b[MAXN+5];

ll calc(int a,int b,int c)
{
    int last;ll ans=0;if(a>b)swap(a,b);
    a/=c;b/=c;
    for(int i=1;i<=a;i=last+1)
    {
        last=min(b/(b/i),a/(a/i));
        ans+=1LL*(f[last]-f[i-1])*(a/i)*(b/i);
    }
    return ans;
}

int main()
{
    f[1]=1;
    for(int i=2;i<=MAXN;i++)
    {
        if(!b[i])s[++num]=i,f[i]=-1;
        for(int j=1;s[j]*i<=MAXN;j++)
        {
            b[s[j]*i]=1;
            if(i%s[j]==0){f[s[j]*i]=0;break;}
            f[s[j]*i]=-f[i];
        }
    }
    for(int i=2;i<=MAXN;i++)f[i]+=f[i-1];
    for(int T=read();T;T--)
    {
        int a=read(),b=read(),c=read(),d=read(),k=read();
        printf("%lld
",calc(b,d,k)-calc(a-1,d,k)-calc(b,c-1,k)+calc(a-1,c-1,k));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/bzoj2301.html