hdu-3388 Coprime---容斥定理&&DFS版
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3388
题目大意:
求同时与m,n互质的第k个数是多少!
解题思路:
和HDU-4135类似,将m和n的最小公倍数素数分解。
然后二分答案,每次求出1-mid中与m和n的最小公倍数互质的数目,大于等于k 右区间 = mid - 1
否则 左区间 = mid + 1
注意,这里不用枚举子集的方式写,因为这样对同一部分需要计算多次lcm,用DFS写不会超时。
注意特判,当n=1且m=1,答案就是k。
注意,这里是;两者都为1的时候特判,不是一者为1的时候特判。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 set<ll>c; 5 void init(ll n)//n质因子分解 6 { 7 for(ll i = 2; i * i <= n; i++) 8 { 9 if(n % i == 0) 10 { 11 c.insert(i); 12 while(n % i == 0)n /= i; 13 } 14 } 15 if(n != 1)c.insert(n); 16 } 17 18 ll ans, tot; 19 ll a[50]; 20 void dfs(ll d, ll t, ll s, ll n) 21 { 22 if(d == tot) 23 { 24 if(t&1)ans -= n / s; 25 else ans += n / s; 26 return; 27 } 28 dfs(d + 1, t, s, n); 29 dfs(d + 1, t + 1, s * a[d], n); 30 } 31 32 const ll INF = 0x3f3f3f3f3f3f3f3f; 33 int main() 34 { 35 ll T, m, n, k, cases = 0; 36 cin >> T; 37 while(T--) 38 { 39 c.clear(); 40 scanf("%lld%lld%lld", &m, &n, &k); 41 if(m == 1 && n == 1) 42 { 43 printf("Case %lld: %lld\n", ++cases, k); 44 continue; 45 } 46 init(m); 47 init(n); 48 tot = 0; 49 for(set<ll>::iterator it = c.begin(); it != c.end(); it++) 50 a[tot++] = *it; 51 ll l = 1, r = INF, answer; 52 while(l <= r) 53 { 54 ll mid = l + (r - l) / 2; 55 ans = 0; 56 dfs(0, 0, 1, mid); 57 if(ans >= k) 58 answer = mid, r = mid - 1; 59 else l = mid + 1; 60 } 61 printf("Case %lld: %lld\n", ++cases, answer); 62 } 63 return 0; 64 }
越努力,越幸运