bzoj 2301: [HAOI2011]Problem b 莫比乌斯反演
2301: [HAOI2011]Problem b
Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 3679 Solved: 1648
[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
#include<bits/stdc++.h> using namespace std; #define ll long long #define esp 0.00000000001 #define pi 4*atan(1) const int N=1e5+10,M=1e7+10,inf=1e9+10,mod=1e9+7; int mu[N], p[N], np[N], cnt, sum[N]; void init() { mu[1]=1; for(int i=2; i<N; ++i) { if(!np[i]) p[++cnt]=i, mu[i]=-1; for(int j=1; j<=cnt && i*p[j]<N; ++j) { int t=i*p[j]; np[t]=1; if(i%p[j]==0) { mu[t]=0; break; } mu[t]=-mu[i]; } } for(int i=1;i<N;i++) sum[i]=sum[i-1]+mu[i]; } ll getans(int b,int d) { if(b>d)swap(b,d); ll ans=0; for(int L=1,R=0;L<=b;L=R+1) { R=min(b/(b/L),d/(d/L)); ans+=(ll)(sum[R]-sum[L-1])*(b/L)*(d/L); } return ans; } int main() { int T; init(); scanf("%d",&T); while(T--) { int a,c,b,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%lld\n",getans(b/k,d/k)+getans((a-1)/k,(c-1)/k)-getans((a-1)/k,d/k)-getans(b/k,(c-1)/k)); } return 0; }