BZOJ2301: [HAOI2011]Problem b
2301: [HAOI2011]Problem b
Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 5876 Solved: 2675
[Submit][Status][Discuss]
Description
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数
Sample Input
2
2 5 1 5 1
1 5 1 5 2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3
HINT
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
思路{
n/k,m/k,转化为gcd(i,j)==1,
那么直接上套路莫比乌斯反演+数论分块就可以了,
再区间加一加,减一减就可以了.
}
#include<bits/stdc++.h> #define LL long long #define RG register #define il inline #define N 50200 #define LL long long using namespace std; bool vis[N]; LL p[N],mu[N]; void pre(){ mu[1]=1; for(int i=2;i<N;++i){ if(!vis[i])mu[i]=-1,p[++p[0]]=i; for(int j=1;j<=p[0]&&p[j]*i<N;++j){ vis[i*p[j]]=true; if(i%p[j])mu[i*p[j]]=-mu[i]; else { mu[i*p[j]]=0; break; } } }for(int i=2;i<N;++i)mu[i]+=mu[i-1]; } LL cal(int n,int m){ LL ans=0; if(n>m)swap(n,m); for(int l=1,r;l<=n;l=r+1){ r=min(n/(n/l),m/(m/l)); ans+=(mu[r]-mu[l-1])*(n/l)*(m/l); }return ans; } int main(){ int T;scanf("%d",&T);pre(); 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; cout<<cal(b,d)+cal(a,c)-cal(a,d)-cal(c,b)<<"\n"; }return 0; }