BZOJ2301:[HAOI2011]Problem b——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=2301

https://www.luogu.org/problemnew/show/P2522

对于给出的n个询问,每次求有多少个数对(x,y),满足axbcyd,且gcd(x,y) = kgcd(x,y)函数为xy的最大公约数。

(哇做完上面那道题之后看所有的莫比乌斯反演都好亲切啊)

这题应该是可以采用选数的方法(然而我翻车太厉害了就不写了)

那么我们思考容斥,就一个简单的二维容斥,solve(n,m)代表有多少个数对(x,y),满足1xn1ym,且gcd(x,y) = k

答案显然为:solve(b,d)-solve(a,d)-solve(b,c)+solve(a,c)

剩下的就是套路了,套路公式参考:模板:数论函数 & 莫比乌斯反演

#include<cstdio>
#include<queue>
#include<map>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e5+5;
int su[N],he[N],miu[N];
void Euler(int n){
    int tot=0;
    miu[1]=1;    
    for(int i=2;i<=n;i++){    
    if(!he[i]){   
        su[++tot]=i;    
        miu[i]=-1;
    }    
    for(int j=1;j<=tot;j++){    
        if(i*su[j]>n)break;    
        he[i*su[j]]=1;   
        if(i%su[j]==0){    
        miu[i*su[j]]=0;break;    
        }    
        else miu[i*su[j]]=-miu[i];  
    }
    }
    for(int i=1;i<=n;i++)miu[i]+=miu[i-1];
    return;
}
int solve(int n,int m){
    int ans=0;
    for(int i=1,j;i<=min(n,m);i=j+1){
    j=min(n/(n/i),m/(m/i));
    ans+=(miu[j]-miu[i-1])*(m/i)*(n/i);
    }
    return ans;
}
int main(){
    int t;
    Euler(50000);
    scanf("%d",&t);
    while(t--){
    int a,b,c,d,k;
    scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    a--;c--;
    a/=k,b/=k,c/=k,d/=k;
    printf("%d\n",solve(b,d)-solve(a,d)-solve(b,c)+solve(a,c));
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-03-23 16:20  luyouqi233  阅读(181)  评论(0编辑  收藏  举报