Codeforces Round #555 (Div. 3)

贪心+模拟大法好!

A、Reachable Numbers

思路:简单模拟。不难发现,通过f函数运算下去的步骤数量不会很多,所以暴力模拟,只要有一个数字第二次出现break即可。

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 LL n;
30 set<LL> st;
31 
32 int main() {
33     while(cin >> n) {
34         st.clear();
35         st.insert(n);
36         while(1) {
37             ++n;
38             while(n % 10 == 0) n /= 10;
39             if(st.count(n)) break;
40             st.insert(n);
41         }
42         cout << st.size() << endl;
43     }
44     return 0;
45 }
View Code

B、Long Number

思路:简单贪心+模拟。为了使得替换得到的数字最大,并且替换的数字必须是连续的,我们只需找到第一个替换的数字满足 $c_i > b_i$ 作为贪心的起点,并且让$ b_i > c_i$ 作为贪心的终点,然后简单模拟一下即可。

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, f[10], b[maxn], c[maxn];
30 string str, ans;
31 bool flag;
32 
33 
34 int main() {
35     while(cin >> n) {
36         cin >> str;
37         ans = "";
38         flag = false;
39         for(int i = 0; i < n; ++i) b[i] = str[i] - '0';
40         for(int i = 1; i <= 9; ++i) cin >> f[i];
41         for(int i = 0; i < n; ++i) c[i] = f[b[i]];
42         for(int i = 0; i < n; ++i) {
43             if(!flag) {
44                 if(b[i] < c[i]) flag = true, ans += c[i] + '0'; // 贪心起点
45                 else ans += str[i];
46             }else {
47                 if(b[i] > c[i]) { // 贪心终点
48                     for(int j = i; j < n; ++j) ans += str[j];
49                     break;
50                 }
51                 else ans += c[i] + '0';
52             }
53         }
54         cout << ans << endl;
55     }
56     return 0;
57 }
View Code

C1、Increasing Subsequence (easy version)

思路:简单模拟即可。

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, lt, rt, cnt, per, a[maxn];
30 string str;
31 
32 int main() {
33     while(cin >> n) {
34         cnt = 0, per = 0;
35         str = "";
36         for(int i = 0; i < n; ++i) cin >> a[i];
37         int i, j;
38         for(i = 0, j = n - 1; i < j;) {
39             if(a[i] > a[j]) {
40                 if(a[j] > per) str += 'R', ++cnt, per = a[j], --j;
41                 else if(a[i] > per) str += 'L', ++cnt, per = a[i], ++i;
42                 else break;
43             }else {
44                 if(a[i] > per) str += 'L', ++cnt, per = a[i], ++i;
45                 else if(a[j] > per) str += 'R', ++cnt, per = a[j], --j;
46                 else break;
47             }
48         }
49         if(i == j && a[j] > per) {
50             if(2 * j >= n - 1) str += 'R', ++cnt;
51             else str += 'L', ++cnt;
52         }
53         cout << cnt << endl;
54         cout << str << endl;
55     }
56     return 0;
57 }
View Code

C2、Increasing Subsequence (hard version)

思路:贪心+简单模拟。①若当前两边i,j指向的数字不同,则直接贪心处理;②若当前两边i,j指向的数字相同,如何选择左边或右边呢?我们只需另外设置2个变量来比较i和j分别能延伸的长度,哪边长就贪心选哪边即可。

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, res1, res2, cnt, per, a[maxn];
30 string str;
31 bool flag;
32 
33 int main() {
34     while(cin >> n) {
35         cnt = 0, per = 0;
36         str = "";
37         for(int i = 0; i < n; ++i) cin >> a[i];
38         int i, j;
39         for(i = 0, j = n - 1; i < j;) {
40             if(a[i] > a[j]) {
41                 flag = false;
42                 if(a[j] > per) str += 'R', ++cnt, per = a[j], --j, flag = true;
43                 if(flag) continue;
44                 if(a[i] > per) str += 'L', ++cnt, per = a[i], ++i, flag = true;
45                 if(!flag) break;
46             }else if(a[j] > a[i]){
47                 flag = false;
48                 if(a[i] > per) str += 'L', ++cnt, per = a[i], ++i, flag = true;
49                 if(flag) continue;
50                 if(a[j] > per) str += 'R', ++cnt, per = a[j], --j, flag = true;
51                 if(!flag) break;
52             }
53             else { // equal
54                 if(a[i] <= per) break;
55                 res1 = res2 = 0;
56                 for(int lt = i; lt + 1 < j && a[lt] < a[lt + 1]; ++lt, ++res1);
57                 for(int rt = j; rt - 1 > i && a[rt - 1] > a[rt]; --rt, ++res2);
58                 if(res1 > res2) str += 'L', ++cnt, per = a[i], ++i;
59                 else str += 'R', ++cnt, per = a[j], --j;
60             }
61         }
62         if(i == j && a[j] > per) {
63             if(2 * j >= n - 1) str += 'R', ++cnt;
64             else str += 'L', ++cnt;
65         }
66         cout << cnt << endl;
67         cout << str << endl;
68     }
69     return 0;
70 }
View Code

D、N Problems During K Days

思路:简单思维+贪心。题意就是要求构造出一个含k个元素的序列满足该序列①是递增的,②其和刚好为n,③ $ a_i < a_{i + 1} \le 2 a_i $。第一直觉就是先给这k个元素分别有序地填上1~k这k个数字,这样一定满足①和③条件,接着自然就想到一个"NO"点和一个"YES"点,即 $\frac{k(k+1)}{2} > n $、当k==1时a[0] =n。剩下的如何分配呢?借助填补1~k这一个“顺子”(来源斗地主)的思想(若是能按“顺子”填补,则一定能满足③这个条件),我们把剩下的 $ now1 = n - \frac{k(k+1)}{2} $ 分成 $ now2 = \frac{now1}{k} $ 组,然后再给每个$a_i$分别都加上 now2,同样得到一个含k个元素的“顺子”(两两之差的绝对值都为1)!剩下1的个数为 $ now3 = now1 \% k $ (不超过k-1)个,为了满足条件①和③,我们从后往前依次贪心给每个 $ a_i $ 加1,加到now3个1就break!不难证明这一定满足条件③。但是!!!有个trick需要特判:也就是剩下1的个数刚好为k-1个的情况:1、当 k ==2时,若a[0]  == 1,说明a[0] * 2 = 2 < a[1] = 3(显然不成立),而其余情况一定成立;2、当 $ k \geq 3 $ 时,先--a[1],++a[k - 1],这个操作不难验证也是正确的。但当 $ k == 3 $ 时,还需要检验1种特殊情况:1、3、4,因为将3减1变成2,4加1变成5后该序列为1,2,5,可知这序列一定不满足情况,其余一定能满足所有条件,这个不难验证!!!

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 LL n, k, now1, now2, now3, a[maxn];
30 
31 int main() {
32     while(cin >> n >> k) {
33         if((1LL + k) * k / 2 > n) {cout << "NO" << endl; continue;}
34         if(k == 1) {cout << "YES\n" << n << endl; continue;}
35         now1 = n - (1LL + k) * k / 2;
36         now2 = now1 / k;
37         now3 = now1 % k;
38         for(int i = 0; i < k; ++i) a[i] = i + 1 + now2;
39         for(int i = k - 1, num = now3; k > 0 && num; --num, --i) ++a[i];
40 
41         if(now3 != k - 1) {
42             cout << "YES" << endl;
43             for(int i = 0; i < k; ++i) cout << a[i] << " \n"[i == k - 1];
44         }else {
45             if(k >= 3) --a[1], ++a[k - 1];
46             if((k == 2 && a[0] == 1) || (k == 3 && a[1] * 2 < a[2])) cout << "NO" << endl;
47             else {
48                 cout << "YES" << endl;
49                 for(int i = 0; i < k; ++i) cout << a[i] << " \n"[i == k - 1];
50             }
51         }
52     }
53     return 0;
54 }
View Code

E、Minimum Array

思路:简单贪心。这个题用vector容器会T到飞qwq,题解是用关联式容器multiset(自动排序),其增删查的时间复杂度均为 $O(log^n) $,用起来非常简单,容易上手!注意到a数组、b数组中所有元素都小于n,那么问题求解就变得简单了:为了使得每个 $a_i$ 各自能匹配到的 $b_j$ 使得 $(a_i + b_j) \% n $ 最小,只需贪心找不小于 $ (n - a_i) $ 的最小值,因为以 $ (n - a_i) $ 为起点的$ b_j$ 和 $ a_i$ 的和取模n的余数为0,往后逐渐增加,循环一圈到 $ (n - a_i - 1) $ 达到最大;若找不到,则取容器中首个元素进行匹配,即离 $ (n-a_i) $ 左边最远的一个,不难证明此时的 $(a_i+b_j) \% n $ 是最小的。时间复杂度为 $O(nlog^n)$。

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 
30 int n, a[maxn], b, pos, siz;
31 multiset<int> st;
32 multiset<int>::iterator it;
33 
34 
35 int main() {
36     while(~scanf("%d", &n)) {
37         st.clear();
38         for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
39         for(int i = 0; i < n; ++i) scanf("%d", &b), st.insert(b);
40         for(int i = 0; i < n; ++i) {
41             it = st.lower_bound(n - a[i]);
42             if(it == st.end()) it = st.begin();
43             printf("%d%c", (a[i] + *it) % n, " \n"[i == n - 1]);
44             st.erase(it);
45         }
46     }
47     return 0;
48 }
View Code

 

posted @ 2019-04-28 13:12  霜雪千年  阅读(409)  评论(0编辑  收藏  举报