Codeforces Round #552 (Div. 3)

本场题目不难,暴力模拟大法好。A~E:模拟+暴力(有些是贪心);F:留坑待填;G:埃氏筛+贪心。

A、Restoring Three Numbers

思路:简单数学。

AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const int maxn = 1e5+5;
27 const int inf = 0x3f3f3f3f;
28 
29 
30 LL x[5], a, b, c;
31 
32 int main() {
33     while(cin >> x[1] >> x[2] >> x[3] >> x[4]) {
34         sort(x + 1, x + 5);
35         b = (x[1] - x[2] + x[3]) / 2;
36         c = x[3] - b;
37         a = x[4] - b - c;
38         cout << a << ' ' << b << ' '  << c << endl;
39     }
40     return 0;
41 }
View Code

B、Make Them Equal

思路:暴力+模拟。只需枚举最终的数组变成的数字(1~100)即可。

AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const int maxn = 105;
27 const int inf = 0x3f3f3f3f;
28 
29 
30 int n, ans, now, cha, a[maxn];
31 bool flag;
32 
33 int main() {
34     while(~scanf("%d", &n)) {
35         for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
36         sort(a, a + n);
37         ans = inf;
38         for(int j = 0; j <= 100; ++j) { // 枚举最终数组中所有的元素变为j
39             now = 0, cha = 0; // 注意:cha的初始值为0,因为1~n每个数都可能与j相同
40             for(int k = 0; k < n; ++k) // 找到第一个与j不同的数求差的绝对值cha
41                 if(a[k] != j) {cha = abs(a[k] - j); break;}
42             for(int k = 0; k < n; ++k) { // 模拟即可
43                 if(a[k] < j) {
44                     if(a[k] + cha == j) ++now;
45                     else break;
46                 }
47                 else if(a[k] > j) {
48                     if(a[k] - cha == j) ++now;
49                     else break;
50                 }
51                 else if(a[k] == j) ++now;
52             }
53             if(now == n) ans = min(ans, cha);
54         }
55         if(ans == inf) puts("-1");
56         else printf("%d\n", ans);
57     }
58     return 0;
59 }
View Code

C、Gourmet Cat

思路:数学+暴力。由题易得一周内猫吃肉的种类依次为 a、b、c、a、c、b、a。若 $ a \geq 3 \land b \geq 2 \land c \geq 2 $,则先算出轮数;(否则)剩下的枚举每一天作为起点,简单暴力模拟即可。

AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const int maxn = 105;
27 const int inf = 0x3f3f3f3f;
28 
29 int a, b, c, d, ans, now1, now2, k, dir0[7] = {0, 1, 2, 0, 2, 1, 0}, cnt[3], cnt1[3];
30 
31 int main() {
32     while(cin >> a>> b >> c) {
33         ans = 0;
34         memset(cnt, 0, sizeof(cnt));
35         if(a >= 3 && b >= 2 && c >= 2) {
36             k = min(a / 3, min(b / 2, c / 2));
37             a -= 3 * k, b -= 2 * k, c -= 2 * k;
38             ans = 7 * k;
39         }
40         cnt[0] = a, cnt[1] = b, cnt[2] = c, now2 = 0;
41         for(int i = 0; i < 7; ++i) { // 枚举每一天作为起点
42             cnt1[0] = cnt[0], cnt1[1] = cnt[1], cnt1[2] = cnt[2], now1 = 0;
43             for(int j = i; ; ++j) { // 模拟
44                 if(cnt1[dir0[j % 7]] > 0) --cnt1[dir0[j % 7]], ++now1;
45                 else break;
46             }
47             now2 = max(now1, now2);
48         }
49         cout << ans + now2 << endl;
50     }
51     return 0;
52 }
View Code

D、Walking Robot

思路:简单贪心+模拟。详细思路见代码注释。

AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const int maxn = 2e5+5;
27 const int inf = 0x3f3f3f3f;
28 
29 int n, b, a, x, y, ans, s[maxn];
30 
31 int main() {
32     while(cin >> n >> x >> y) {
33         ans = 0; b = x, a = y;
34         for(int i = 0; i < n; ++i) cin >> s[i];
35         for(int i = 0; i < n; ++i) {
36             if(s[i]) { // 若被光照
37                 if(b) { // 先考虑1个b转换成1个a
38                     if(a + 1 <= y) --b, ++a, ++ans; // 最大不超过y
39                     else if(a) --a, ++ans; // 不能转,则先减去a
40                     else if(b) --b, ++ans; // a为0不能继续减,才看b是否剩余
41                     else break;
42                 }
43                 else if(a) --a, ++ans; // 没有b,则只能减去a
44                 else break; // 没法减则退出
45             }else { // 没有被光照,不能转
46                 if(a) --a, ++ans; // 先考虑a
47                 else if(b) --b, ++ans; // a不能减,再考虑b,因为b的作用遇到光时能产生一个a
48                 else break; // 没法减则退出
49             }
50         }
51         cout << ans << endl;
52     }
53     return 0;
54 }
View Code

E、Two Teams

思路:题意很简单:每次找当前队列中技能最大的学生,向左向右分别连续选择k个学生作为自己的队员。①暴力险过。②换种思路:用大根堆维护当前序列的最大值,同时标记每个元素分别向前、向后走的第一个位置,剩下的暴力模拟即可。

AC代码一:暴力解。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const int maxn = 2e5+5;
27 const int inf = 0x3f3f3f3f;
28 
29 int n, k, a, ans[maxn], siz, now, cnt, pos, mp[maxn], lt, rt;
30 vector<int> vec;
31 set<int> stl;
32 set<int>::iterator it;
33 
34 int main() {
35     while(~scanf("%d%d", &n, &k)) {
36         memset(ans, 0, sizeof(ans));
37         memset(mp, 0, sizeof(mp));
38         vec.clear();
39         stl.clear();
40         cnt = 0;
41         for(int i = 0; i < n; ++i) {
42             scanf("%d", &a);
43             vec.push_back(a);
44             mp[a] = i;
45             stl.insert(a);
46         }
47         while((siz = stl.size()) != 0) {
48             it = stl.end();
49             --it;
50             ++cnt;
51             if(cnt & 1) now = 1;
52             else now = 2;
53             pos = find(vec.begin(), vec.end(), *it) - vec.begin();
54             lt = max(0, pos - k), rt = min(siz - 1, pos + k);
55             for(int i = lt; i <= rt; ++i) {
56                 ans[mp[vec[i]]] = now;
57                 stl.erase(vec[i]);
58             }
59             vec.erase(vec.begin() + lt, vec.begin() + rt + 1);
60         }
61         for(int i = 0; i < n; ++i) printf("%d", ans[i]);
62         puts("");
63     }
64     return 0;
65 }
View Code

AC代码二:优化解。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const int maxn = 2e5+5;
27 const int inf = 0x3f3f3f3f;
28 
29 int n, k, a, now1, now2, flag, p1, p2, num, ans[maxn], nex[maxn], per[maxn];
30 
31 priority_queue<pair<int, int> > que;
32 bool vis[maxn];
33 
34 
35 int main() {
36     while(~scanf("%d%d", &n, &k)) {
37         while(!que.empty()) que.pop();
38         memset(ans, 0, sizeof(ans));
39         memset(per, 0, sizeof(per));
40         memset(nex, 0, sizeof(nex));
41         flag = 1;
42         memset(vis, false, sizeof(vis));
43         for(int i = 1; i <= n; ++i) {
44             scanf("%d", &a);
45             que.push(make_pair(a, i));
46             per[i] = i - 1;
47             nex[i] = i + 1;
48         }
49         while(!que.empty()) {
50             now1 = que.top().first, now2 = que.top().second, que.pop();
51             if(vis[now2]) continue;
52             vis[now2] = true;
53             flag = !flag;
54             p1 = per[now2], p2 = nex[now2], ans[now2] = flag + 1;
55             num = k;
56             while(num > 0 && p1 > 0) vis[p1] = true, ans[p1] = flag + 1, --num, p1 = per[p1];
57             num = k;
58             while(num > 0 && p2 <= n) vis[p2] = true, ans[p2] = flag + 1, --num, p2 = nex[p2];
59             per[p2] = p1, nex[p1] = p2;
60         }
61         for(int i = 1; i <= n; ++i) printf("%d", ans[i]);
62         puts("");
63     }
64     return 0;
65 }
View Code

G、Minimum Possible LCM

思路:埃氏筛+贪心。题意就是找出2个数使其最小公倍数最小。题目虽然给的时限是4s,但我们要换种优雅的方式来暴力,即来枚举每一个gcd(求lcm需要先求出2个数的gcd)。借用埃氏筛思想,公约数为gcd的步长增长,不难想到,头2次出现的这2个数的最小公倍数一定为gcd时的最小lcm,那么我们就可以用 $O(nlog^n)$的时间复杂度,大约是 $1.6 \times 10^8 $(1s的极限是$ 1.0 \times 10^8 $)即用1s多就可以过掉此题!

AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <iomanip>
 8 #include <complex>
 9 #include <string>
10 #include <vector>
11 #include <set>
12 #include <map>
13 #include <list>
14 #include <deque>
15 #include <queue>
16 #include <stack>
17 #include <bitset>
18 using namespace std;
19 typedef long long LL;
20 typedef unsigned long long ULL;
21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左
22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向
23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
24 const double eps = 1e-6;
25 const double PI = acos(-1.0);
26 const LL maxn = 1e7+5;
27 const LL inf = 1LL << 62;
28 
29 
30 int n, num, p1, p2, per1, per2, siz;
31 LL ans, now0, now1, now2, a;
32 
33 bool vis[maxn];
34 
35 vector<int> vec[maxn];
36 
37 
38 int main() {
39     while(~scanf("%d", &n)) {
40         ans = inf;
41         per1 = per2 = 0;
42         for(LL i = 0LL; i < maxn; ++i) vec[i].clear();
43         memset(vis, false, sizeof(vis));
44         for(int i = 1; i <= n; ++i) {
45             scanf("%lld", &a);
46             vec[a].push_back(i);
47             vis[a] = true; // 标记出现的元素
48         }
49         for(LL i = 1LL; i < maxn; ++i) {
50             num = 0;
51             for(LL j = i; j < maxn && num < 2; j += i) {
52                 if(!vis[j]) continue;
53                 if(num == 0) { // 第一次出现
54                     siz = vec[j].size();
55                     if(siz == 1) {
56                         ++num;
57                         p1 = vec[j][0];
58                         now1 = j;
59                     }
60                     else {
61                         num += 2; // 头2个
62                         p1 = vec[j][0], p2 = vec[j][1];
63                         now1 = j, now2 = j;
64                     }
65                 }else { // 第二次出现
66                     ++num;
67                     now2 = j;
68                     p2 = vec[j][0];
69                 }
70             }
71             if(num == 2) {
72                 now0 = now1 / i * now2;
73                 if(ans > now0) {
74                     ans = now0;
75                     per1 = p1, per2 = p2;
76                 }
77             }
78         }
79         if(per1 > per2) swap(per1, per2);
80         printf("%d %d\n", per1, per2);
81     }
82     return 0;
83 }
View Code

 

posted @ 2019-04-17 19:07  霜雪千年  阅读(533)  评论(0编辑  收藏  举报