题目:
对于给出的 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 Input22 5 1 5 11 5 1 5 2Sample Output
14
3
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
思路:
首先把问题化简成,求有多少个数对(x,y)满足1<=x<=n,1<=y<=m且gcd(x,y)=1
这里我们只需要求f(1)即可
优化的关键是快速枚举除法取值,太厉害了
代码:
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; const int N = 50000; bool prime[N]; int u[N], su[N];//su是u的前缀和 void getu() { for (int i = 0; i < N; i++)prime[i] = true, u[i] = 1; prime[1] = false; for (int i = 2; i < N; i++)if (prime[i])for (int j = 1; i* j < N; j++) prime[i*j] = false, u[i*j] *= -1 * (j%i != 0); su[0] = u[0]; for (int i = 1; i < N; i++)su[i] = su[i - 1] + u[i]; } int f(int n, int m)//有多少个数对(x,y)满足1<=x<=n,1<=y<=m且gcd(x,y)=1 { int res = 0; for (int i = 1, key; i <= n && i <= m; i = key + 1) { key = min(n / (n / i), m / (m / i)); res += (n / i)*(m / i)*(su[key] - su[i - 1]); } return res; } int main() { int n, a, b, c, d, k; scanf("%d", &n); getu(); while (n--) { scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); a--, c--; a /= k, b /= k, c /= k, d /= k; printf("%d\n", f(b, d) - f(a, d) - f(b, c) + f(a, c)); } return 0; }