BZOJ2301:[HAOI2011]Problem b——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2301
https://www.luogu.org/problemnew/show/P2522
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
(哇做完上面那道题之后看所有的莫比乌斯反演都好亲切啊)
这题应该是可以采用选数的方法(然而我翻车太厉害了就不写了)
那么我们思考容斥,就一个简单的二维容斥,solve(n,m)代表有多少个数对(x,y),满足1≤x≤n,1≤y≤m,且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/+
+++++++++++++++++++++++++++++++++++++++++++