题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1695
题目大意:
求解区间[1, n]和[1, m]中有多少对不同的x和y使得gcd(x, y) == k
其中x=5 y=7和x=7 y=5是同一对
解题思路:
首先如果gcd为k说明[1, n]中只有k的倍数为x,同理在[1, m]中也只有k的倍数为y。
所以如果先特判,k=0或者k>n或者k>m都是不存在解的情况。
之后n /= k, m /= k,这是之选出k的倍数,作为x和y,并且gcd(x, y) = k,就是等价于求在现在的1-n区间和1-m区间中求互质对数。
还需考虑重复的情况,所以枚举m的时候求区间[m, n]与m互质的数,这样不会重复枚举。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e6 + 10; 5 ll a[50], tot; 6 ll gcd(ll a, ll b) 7 { 8 return b == 0 ? a : gcd(b, a % b); 9 } 10 void init(ll n)//求出n的素因子 11 { 12 tot = 0; 13 for(ll i = 2; i * i <= n; i++) 14 { 15 if(n % i == 0) 16 { 17 a[tot++] = i; 18 while(n % i == 0)n /= i; 19 } 20 } 21 if(n != 1)a[tot++] = n; 22 } 23 ll sum(ll m)//求[1, m]中与n互质的个数 24 { 25 ll ans = 0; 26 for(int i = 1; i < (1 << tot); i++)//a数组的子集 27 { 28 ll num = 0; 29 for(int j = i; j; j >>= 1)if(j & 1)num++;//统计i的二进制中1的个数 30 ll lcm = 1; 31 for(int j = 0; j < tot; j++) 32 if((1 << j) & i) 33 { 34 lcm = lcm / gcd(lcm, a[j]) * a[j]; 35 if(lcm > m)break; 36 } 37 if(num & 1)ans += m / lcm;//奇数加上 38 else ans -= m / lcm;//偶数减去 39 } 40 return m - ans; 41 } 42 int main() 43 { 44 int T, cases = 0, a, b, n, m, k; 45 cin >> T; 46 while(T--) 47 { 48 ll ans; 49 scanf("%d%d%d%d%d", &a, &n, &b, &m, &k); 50 if(k == 0 || n < k || m < k)ans = 0; 51 else 52 { 53 n /= k, m /= k; 54 if(n < m)swap(n, m); 55 ans = n; 56 for(int i = 2; i <= m; i++) 57 { 58 init(i); 59 //cout<<ans<<endl; 60 ans += sum(n) - sum(i - 1); 61 } 62 } 63 cout<<"Case "<<++cases<<": "<<ans<<endl; 64 } 65 return 0; 66 }