Problem b
Time Limit: 50 Sec Memory Limit: 256 MB
Description
对于给出的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
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数。
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
Solution
显然可以考虑容斥,分为四块来做,剩下的就是:
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include<bits/stdc++.h> using namespace std; typedef long long s64;
const int ONE = 50005;
int T; int Ax,Bx,Ay,By,k; bool isp[ONE]; int prime[ONE],p_num; int miu[ONE],sum_miu[ONE]; s64 Ans;
int get() { int res=1,Q=1; char c; while( (c=getchar())<48 || c>57) if(c=='-')Q=-1; if(Q) res=c-48; while((c=getchar())>=48 && c<=57) res=res*10+c-48; return res*Q; }
void Getmiu(int MaxN) { miu[1] = 1; for(int i=2; i<=MaxN; i++) { if(!isp[i]) prime[++p_num] = i, miu[i] = -1; for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++) { isp[i * prime[j]] = 1; if(i%prime[j] == 0) { miu[i * prime[j]] = 0; break; } miu[i * prime[j]] = -miu[i]; } miu[i] += miu[i-1]; } }
s64 Calc(int n,int m) { if(n > m) swap(n,m);
int N = n/k, M = m/k; Ans = 0; for(int i=1,j=0; i<=N; i=j+1) { j = min(N/(N/i), M/(M/i)); Ans += (s64)(N/i) * (M/i) * (miu[j] - miu[i-1]); }
return Ans; }
void Solve() { Ax=get(); Bx=get(); Ay=get(); By=get(); k=get(); printf("%lld\n", Calc(Bx,By) - Calc(Ax-1,By) - Calc(Ay-1,Bx) + Calc(Ax-1,Ay-1)); }
int main() { Getmiu(ONE-1); T=get(); while(T--) Solve(); }
|