1. 程式人生 > >hdu-1695 GCD---容斥定理

hdu-1695 GCD---容斥定理

amp color ret namespace () 1的個數 ini names target

題目鏈接:

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 }

hdu-1695 GCD---容斥定理