[bzoj2301] [HAOI2011]Problem b

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

题解:我们可以同时除以k,然后容斥原理,题意转换为求$1\leqslant x \leqslant a1 , 1\leqslant y\leqslant 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} \rfloor*\lfloor \frac{b1}{d} \rfloor$

然后$\lfloor \frac{a1}{d} \rfloor$只有$\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\n",calc(b,d,k)-calc(a-1,d,k)-calc(b,c-1,k)+calc(a-1,c-1,k));
    }
    return 0;
}

 

posted @ 2017-03-26 12:03  FallDream  阅读(172)  评论(0编辑  收藏  举报