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 }

 

posted @ 2018-05-23 18:28  _努力努力再努力x  阅读(145)  评论(0编辑  收藏  举报