P2522 [HAOI2011]Problem b
Posted five20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2522 [HAOI2011]Problem b相关的知识,希望对你有一定的参考价值。
题目描述
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
输入输出格式
输入格式:第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
输出格式:共n行,每行一个整数表示满足要求的数对(x,y)的个数
输入输出样例
输入样例#1:
2
2 5 1 5 1
1 5 1 5 2
输出样例#1:
14
3
说明
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
Solution:
本题莫比乌斯反演+简单容斥。
先考虑$1,n$和$1,m$范围内的情况,那么做法就和上题的ZAP类似,过程就不多赘述。
那么容斥一下,答案就是$(b,d)-(a-1,d)-(b,c-1)+(a-1,c-1)$啦。
时间复杂度$O(qsqrt n)$。
代码:
/*Code by 520 -- 9.10*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=50005; int a,b,c,d,k,ans; int mu[N],prime[N],cnt; bool isprime[N]; int gi(){ int a=0;char x=getchar(); while(x<‘0‘||x>‘9‘)x=getchar(); while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+(x^48),x=getchar(); return a; } il int solve(int n,int m){ int ans=0,p; if(n>m) swap(n,m); n/=k,m/=k; for(int i=1;i<=n;i=p+1){ p=min(n/(n/i),m/(m/i)); ans+=(n/i)*(m/i)*(mu[p]-mu[i-1]); } return ans; } int main(){ mu[1]=1; For(i,2,50000){ if(!isprime[i]) mu[i]=-1,prime[++cnt]=i; for(RE int j=1;j<=cnt&&prime[j]*i<=50000;j++){ isprime[i*prime[j]]=1; if(i%prime[j]==0)break; mu[i*prime[j]]=-mu[i]; } } For(i,1,50000) mu[i]+=mu[i-1]; int T=gi(); while(T--){ a=gi(),b=gi(),c=gi(),d=gi(),k=gi(); printf("%d ",solve(b,d)-solve(a-1,d)-solve(b,c-1)+solve(a-1,c-1)); } return 0; }
以上是关于P2522 [HAOI2011]Problem b的主要内容,如果未能解决你的问题,请参考以下文章