题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1695
题目大意:
给你a, b, c, d, k; 找出这样的一队 x, y, 使得 gcd(x , y) = k, 并且x ∈[1, b], y ∈ [1, d], 问有多少对符合要求的(x, y)。
------------------------------------------------------------------------------
思路: gcd(x, y) == k 说明x,y都能被k整除, 但是能被k整除的未必gcd=k , 必须还要满足互质关系. 问题就转化为了求1~a/k 和 1~b/k间互质对数的问题可以把a设置为小的那个数, 那么以y>x来保持唯一性(题目要求, 比如[1,3] =[3,1] )
接下来份两种情况:
1. y <= a , 那么对数就是 1~a的欧拉函数的累计和(容易想到)
2. y >= a , 这个时候欧拉函数不能用了,怎么做? 可以用容斥原理,把y与1~a互质对数问题转换为y的质数因子在1~a范围内能整除的个数(质数分解和容斥关系),dfs一下即可。
代码如下;
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> #include <set> #include <map> #include <queue> using namespace std; /* freopen("input.txt", "r", stdin); //读数据 freopen("output.txt", "w", stdout); //注释掉此句则输出到控制台 */ const int N = 100005; typedef long long LL; LL prime[N]; LL phi[N]; bool is_prime[N]; vector<LL> link[N]; void get_phi() //筛法欧拉函数 { LL i, j, k = 0; phi[1] = 1; for(i = 2; i < N; i++) { if(is_prime[i] == false) { prime[k++] = i; phi[i] = i-1; } for(j = 0; j<k && i*prime[j]<N; j++) { is_prime[ i*prime[j] ] = true; if(i%prime[j] == 0) { phi[ i*prime[j] ] = phi[i] * prime[j]; break; } else { phi[ i*prime[j] ] = phi[i] * (prime[j]-1); } } } } void init() //求每一个数的质因数,vector储存 { LL i, j, k; for(i = 1; i < N; i++) { k = i; for(j = 0; prime[j]*prime[j] <= k; j++) { if(k%prime[j] == 0) { link[i].push_back(prime[j]); while(k%prime[j] == 0) k /= prime[j]; } if(k == 1) break; } if(k > 1) link[i].push_back(k); } } LL dfs(LL a, LL b, LL cur) //容斥原理计算 { LL i, k, res = 0; for(i = a; i < link[cur].size(); i++) { k = b/link[cur][i]; res += k - dfs(i+1, k, cur); } return res; } int main() { LL i, a, b, c, d, k, sum, t, zz = 1; get_phi(); init(); scanf("%I64d", &t); while(t--) { scanf("%I64d %I64d %I64d %I64d %I64d", &a, &b, &c, &d, &k); if(k == 0 || k > b || k > d) { printf("Case %I64d: 0\n", zz++); continue; } if(b > d) swap(b, d); b /= k; d /= k; sum = 0; for(i = 1; i <= b; i++) { sum += phi[i]; } for(i = b+1; i <= d; i++) { sum += b - dfs(0, b, i); } printf("Case %I64d: %I64d\n", zz++, sum); } return 520; }