codeforces #595 div3 题解

A. Yet Another Dividing into Teams

Description

Solution

 1 #include <algorithm>
 2 #include <cctype>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <cstring>
 7 #include <iostream>
 8 #include <map>
 9 #include <queue>
10 #include <set>
11 #include <stack>
12 #if __cplusplus >= 201103L
13 #include <unordered_map>
14 #include <unordered_set>
15 #endif
16 #include <vector>
17 #define lson rt << 1, l, mid
18 #define rson rt << 1 | 1, mid + 1, r
19 #define LONG_LONG_MAX 9223372036854775807LL
20 #define ll LL
21 using namespace std;
22 typedef long long ll;
23 typedef long double ld;
24 typedef unsigned long long ull;
25 typedef pair<int, int> P;
26 int n, m, k;
27 const int maxn = 1e5 + 10;
28 template <class T>
29 inline T read()
30 {
31     int f = 1;
32     T ret = 0;
33     char ch = getchar();
34     while (!isdigit(ch))
35     {
36         if (ch == '-')
37             f = -1;
38         ch = getchar();
39     }
40     while (isdigit(ch))
41     {
42         ret = (ret << 1) + (ret << 3) + ch - '0';
43         ch = getchar();
44     }
45     ret *= f;
46     return ret;
47 }
48 template <class T>
49 inline void write(T n)
50 {
51     if (n < 0)
52     {
53         putchar('-');
54         n = -n;
55     }
56     if (n >= 10)
57     {
58         write(n / 10);
59     }
60     putchar(n % 10 + '0');
61 }
62 template <class T>
63 inline void writeln(const T &n)
64 {
65     write(n);
66     puts("");
67 }
68 int a[maxn];
69 int main(int argc, char const *argv[])
70 {
71 #ifndef ONLINE_JUDGE
72     freopen("in.txt", "r", stdin);
73     freopen("out.txt", "w", stdout);
74 #endif
75     int t = read<int>();
76     while (t--)
77     {
78         n = read<int>();
79         for (int i = 0; i < n; i++)
80             a[i] = read<int>();
81         sort(a, a + n);
82         int f = 0;
83         for (int i = 1; i < n; i++)
84             if (a[i] == a[i - 1] + 1)
85                 ++f;
86         if (f)
87             puts("2");
88         else
89             puts("1");
90     }
91     return 0;
92 }
View Code

B. Books Exchange

Description

给出一个置换群,求每个循环的阶

Solution

dfs瞎搜一手

  1 #include <algorithm>
  2 #include <cctype>
  3 #include <cmath>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <iostream>
  8 #include <map>
  9 #include <queue>
 10 #include <set>
 11 #include <stack>
 12 #if __cplusplus >= 201103L
 13 #include <unordered_map>
 14 #include <unordered_set>
 15 #endif
 16 #include <vector>
 17 #define lson rt << 1, l, mid
 18 #define rson rt << 1 | 1, mid + 1, r
 19 #define LONG_LONG_MAX 9223372036854775807LL
 20 #define ll LL
 21 using namespace std;
 22 typedef long long ll;
 23 typedef long double ld;
 24 typedef unsigned long long ull;
 25 typedef pair<int, int> P;
 26 int n, m, k;
 27 const int maxn = 2e5 + 10;
 28 template <class T>
 29 inline T read()
 30 {
 31     int f = 1;
 32     T ret = 0;
 33     char ch = getchar();
 34     while (!isdigit(ch))
 35     {
 36         if (ch == '-')
 37             f = -1;
 38         ch = getchar();
 39     }
 40     while (isdigit(ch))
 41     {
 42         ret = (ret << 1) + (ret << 3) + ch - '0';
 43         ch = getchar();
 44     }
 45     ret *= f;
 46     return ret;
 47 }
 48 template <class T>
 49 inline void write(T n)
 50 {
 51     if (n < 0)
 52     {
 53         putchar('-');
 54         n = -n;
 55     }
 56     if (n >= 10)
 57     {
 58         write(n / 10);
 59     }
 60     putchar(n % 10 + '0');
 61 }
 62 template <class T>
 63 inline void writeln(const T &n)
 64 {
 65     write(n);
 66     puts("");
 67 }
 68 int a[maxn], vis[maxn], step;
 69 void dfs(int u, int f)
 70 {
 71     if (a[u] == f)
 72     {
 73         vis[u] = step;
 74         return;
 75     }
 76     step++;
 77     dfs(a[u], f);
 78     vis[u] = step;
 79 }
 80 int main(int argc, char const *argv[])
 81 {
 82 #ifndef ONLINE_JUDGE
 83     freopen("in.txt", "r", stdin);
 84     freopen("out.txt", "w", stdout);
 85 #endif
 86     int t = read<int>();
 87     while (t--)
 88     {
 89         n = read<int>();
 90         memset(vis, 0, sizeof(int) * (n + 1));
 91         for (int i = 1; i <= n; i++)
 92             a[i] = read<int>();
 93         for (int i = 1; i <= n; i++)
 94         {
 95             if (!vis[i])
 96             {
 97                 step = 1;
 98                 dfs(i, i);
 99             }
100         }
101         for (int i = 1; i <= n; i++)
102             printf("%d ", vis[i]);
103         puts("");
104     }
105     return 0;
106 }
View Code

C. Good Numbers

Description

给一个数n,找出一个最小的m使得m>=n,且m是3的幂次之和,同一幂次最多出现依次

Solution

十进制分解为三进制,当某一位是2或3(上一位进位而来)时,当前位赋值0,下一位++,注意判断最后进位,以及最后更新位置之前赋0

三进制转回十进制即为答案

  1 #include <algorithm>
  2 #include <cctype>
  3 #include <cmath>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <iostream>
  8 #include <map>
  9 #include <queue>
 10 #include <set>
 11 #include <stack>
 12 #if __cplusplus >= 201103L
 13 #include <unordered_map>
 14 #include <unordered_set>
 15 #endif
 16 #include <vector>
 17 #define lson rt << 1, l, mid
 18 #define rson rt << 1 | 1, mid + 1, r
 19 #define LONG_LONG_MAX 9223372036854775807LL
 20 #define ll LL
 21 using namespace std;
 22 typedef long long ll;
 23 typedef long double ld;
 24 typedef unsigned long long ull;
 25 typedef pair<int, int> P;
 26 ull n, m, k;
 27 const int maxn = 1e5 + 10;
 28 template <class T>
 29 inline T read()
 30 {
 31     int f = 1;
 32     T ret = 0;
 33     char ch = getchar();
 34     while (!isdigit(ch))
 35     {
 36         if (ch == '-')
 37             f = -1;
 38         ch = getchar();
 39     }
 40     while (isdigit(ch))
 41     {
 42         ret = (ret << 1) + (ret << 3) + ch - '0';
 43         ch = getchar();
 44     }
 45     ret *= f;
 46     return ret;
 47 }
 48 template <class T>
 49 inline void write(T n)
 50 {
 51     if (n < 0)
 52     {
 53         putchar('-');
 54         n = -n;
 55     }
 56     if (n >= 10)
 57     {
 58         write(n / 10);
 59     }
 60     putchar(n % 10 + '0');
 61 }
 62 template <class T>
 63 inline void writeln(const T &n)
 64 {
 65     write(n);
 66     puts("");
 67 }
 68 ull p[50];
 69 void init()
 70 {
 71     p[0] = 1;
 72     for (int i = 1; i < 50; i++)
 73         p[i] = p[i - 1] * 3;
 74 }
 75 vector<int> t3;
 76 ull solve()
 77 {
 78     t3.clear();
 79     while (n)
 80     {
 81         t3.emplace_back(n % 3);
 82         n /= 3;
 83     }
 84     int sz = t3.size();
 85     int f = -1;
 86     for (int i = 0; i < sz; i++)
 87         if (t3[i] == 2 || t3[i] == 3)
 88         {
 89             f = i;
 90             if (i != sz - 1)
 91             {
 92                 t3[i] = 0;
 93                 t3[i + 1]++;
 94             }
 95             else
 96             {
 97                 t3[i] = 0;
 98                 t3.emplace_back(1);
 99             }
100         }
101     sz = t3.size();
102     ull res = 0;
103     if (f != -1)
104         for (int i = 0; i < f; i++)
105             t3[i] = 0;
106     for (int i = 0; i < sz; i++)
107         if (t3[i])
108             res += p[i];
109     return res;
110 }
111 int main(int argc, char const *argv[])
112 {
113 #ifndef ONLINE_JUDGE
114     freopen("in.txt", "r", stdin);
115     // freopen("out.txt", "w", stdout);
116 #endif
117     init();
118     int t = read<int>();
119     while (t--)
120     {
121         n = read<ull>();
122         writeln(solve());
123     }
124     return 0;
125 }
View Code

D1. Too Many Segments

Description

给n个区间,一个上界k
问最少删除多少区间,使得区间内任一点的覆盖数不大于k
 

Solution

贪心策略,从左往右找每个需要删区间的点,对于区间选择采取满足l<=i且r最大
由于区间和n值较小,O(n^3)亦可过
  1 /*
  2     给n个区间,一个上界k
  3     问最少删除多少区间,使得区间内任一点的覆盖数不大于k
  4     贪心策略,从左往右找每个需要删区间的点,对于区间选择采取满足l<=i且r最大
  5     由于区间和n值较小,O(n^3)亦可过
  6 */
  7 #include <algorithm>
  8 #include <cctype>
  9 #include <cmath>
 10 #include <cstdio>
 11 #include <cstdlib>
 12 #include <cstring>
 13 #include <iostream>
 14 #include <map>
 15 #include <numeric>
 16 #include <queue>
 17 #include <set>
 18 #include <stack>
 19 #if __cplusplus >= 201103L
 20 #include <unordered_map>
 21 #include <unordered_set>
 22 #endif
 23 #include <vector>
 24 #define lson rt << 1, l, mid
 25 #define rson rt << 1 | 1, mid + 1, r
 26 #define LONG_LONG_MAX 9223372036854775807LL
 27 #define ll LL
 28 using namespace std;
 29 typedef long long ll;
 30 typedef long double ld;
 31 typedef unsigned long long ull;
 32 typedef pair<int, int> P;
 33 int n, m, k;
 34 const int maxn = 1e5 + 10;
 35 template <class T>
 36 inline T read()
 37 {
 38     int f = 1;
 39     T ret = 0;
 40     char ch = getchar();
 41     while (!isdigit(ch))
 42     {
 43         if (ch == '-')
 44             f = -1;
 45         ch = getchar();
 46     }
 47     while (isdigit(ch))
 48     {
 49         ret = (ret << 1) + (ret << 3) + ch - '0';
 50         ch = getchar();
 51     }
 52     ret *= f;
 53     return ret;
 54 }
 55 template <class T>
 56 inline void write(T n)
 57 {
 58     if (n < 0)
 59     {
 60         putchar('-');
 61         n = -n;
 62     }
 63     if (n >= 10)
 64     {
 65         write(n / 10);
 66     }
 67     putchar(n % 10 + '0');
 68 }
 69 template <class T>
 70 inline void writeln(const T &n)
 71 {
 72     write(n);
 73     puts("");
 74 }
 75 struct node
 76 {
 77     int l, r, idx;
 78     node() {}
 79     node(int l, int r, int idx)
 80     {
 81         this->l = l, this->r = r, this->idx = idx;
 82     }
 83     bool operator<(const node &t1) const
 84     {
 85         if (r == t1.r)
 86             return l < t1.l;
 87         return r < t1.l;
 88     }
 89 };
 90 
 91 vector<node> vec;
 92 int p[202], del[202];
 93 int main(int argc, char const *argv[])
 94 {
 95 #ifndef ONLINE_JUDGE
 96     freopen("in.txt", "r", stdin);
 97     // freopen("out.txt", "w", stdout);
 98 #endif
 99     n = read<int>(), k = read<int>();
100     int maxx = 0;
101     for (int i = 1; i <= n; i++)
102     {
103 
104         int x = read<int>(), y = read<int>();
105         maxx = max(maxx, y);
106         vec.emplace_back(x, y, i);
107         for (int j = x; j <= y; j++)
108             ++p[j];
109     }
110     for (int i = 1; i <= maxx; i++)
111     {
112         while (p[i] > k)
113         {
114             int rr = 0, delid = -1;
115             for (int j = 0; j < n; j++)
116                 if (!del[j] && vec[j].l <= i && vec[j].r > rr)
117                 {
118                     rr = vec[j].r;
119                     delid = j;
120                 }
121             for (int j = vec[delid].l; j <= vec[delid].r; j++)
122                 --p[j];
123             del[delid] = 1;
124         }
125     }
126     int res = accumulate(del, del + n, 0);
127     writeln(res);
128     for (int i = 0; i < n; i++)
129         if (del[i])
130             write(i + 1), putchar(' ');
131     return 0;
132 }
View Code

D2. Too Many Segments

Description

同上一题

Solution

官方题解没看懂,看了大佬博客得知的贪心思路。

要想最少删减区间,则要使删减的区间尽可能的大,留下的区间尽可能少重叠(感觉前一句话更好理解)。

考虑区间右端点排序,线段树维护区间最大值,询问一个区间时,如果当前区间加上后最值小于k说明可以加入,否则加入删除边集。

为什么右端点排序时正确的呢,右端点排序后,相同右端点的区间中一定是左端点最小的首先出现,且此时大概率会出现当前区间覆盖之前已访问区间的情况,

也就是说,此时的区间一定是当前右端点最长的一个,且和前面区间很大可能重叠。这时线段树查询区间最值,如果大于等于k说明不能满足,删除这条边就是贪心最优策略。

  1 #include <algorithm>
  2 #include <cctype>
  3 #include <cmath>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <iostream>
  8 #include <map>
  9 #include <queue>
 10 #include <set>
 11 #include <stack>
 12 #if __cplusplus >= 201103L
 13 #include <unordered_map>
 14 #include <unordered_set>
 15 #endif
 16 #include <vector>
 17 #define lson rt << 1
 18 #define rson rt << 1 | 1
 19 #define LONG_LONG_MAX 9223372036854775807LL
 20 #define pblank putchar(' ')
 21 #define ll LL
 22 using namespace std;
 23 typedef long long ll;
 24 typedef long double ld;
 25 typedef unsigned long long ull;
 26 typedef pair<int, int> P;
 27 int n, m, k;
 28 const int maxn = 2e5 + 10;
 29 template <class T>
 30 inline T read()
 31 {
 32     int f = 1;
 33     T ret = 0;
 34     char ch = getchar();
 35     while (!isdigit(ch))
 36     {
 37         if (ch == '-')
 38             f = -1;
 39         ch = getchar();
 40     }
 41     while (isdigit(ch))
 42     {
 43         ret = (ret << 1) + (ret << 3) + ch - '0';
 44         ch = getchar();
 45     }
 46     ret *= f;
 47     return ret;
 48 }
 49 template <class T>
 50 inline void write(T n)
 51 {
 52     if (n < 0)
 53     {
 54         putchar('-');
 55         n = -n;
 56     }
 57     if (n >= 10)
 58     {
 59         write(n / 10);
 60     }
 61     putchar(n % 10 + '0');
 62 }
 63 template <class T>
 64 inline void writeln(const T &n)
 65 {
 66     write(n);
 67     puts("");
 68 }
 69 struct node
 70 {
 71     int l, r, idx;
 72     node() {}
 73     node(int ll, int rr, int i) : l(ll), r(rr), idx(i) {}
 74     bool operator<(const node &t) const
 75     {
 76         if (r == t.r)
 77             return l < t.l;
 78         return r < t.r;
 79     }
 80 };
 81 vector<node> vec;
 82 struct Node
 83 {
 84     int l, r;
 85     ll sum, lazy;
 86 } tr[maxn << 2];
 87 inline void pushup(int rt)
 88 {
 89     tr[rt].sum = max(tr[lson].sum, tr[rson].sum);
 90 }
 91 inline void pushdown(int rt)
 92 {
 93 
 94     if (tr[rt].lazy)
 95     {
 96         tr[lson].lazy += tr[rt].lazy; //注意此题是区间加,固懒标记也应该是累加而不是覆盖
 97         tr[rson].lazy += tr[rt].lazy;
 98         tr[lson].sum += tr[rt].lazy;
 99         tr[rson].sum += tr[rt].lazy;
100         tr[rt].lazy = 0;
101     }
102 }
103 void build(int rt, int l, int r)
104 {
105     tr[rt].l = l;
106     tr[rt].r = r;
107     tr[rt].lazy = tr[rt].sum = 0;
108     if (l == r)
109         return;
110     int mid = l + r >> 1;
111     build(lson, l, mid);
112     build(rson, mid + 1, r);
113 }
114 void update(int rt, int L, int R, ll v)
115 {
116     int l = tr[rt].l;
117     int r = tr[rt].r;
118     if (l >= L && r <= R)
119     {
120         tr[rt].lazy += v;
121         tr[rt].sum += v;
122         return;
123     }
124     pushdown(rt); //当前区间没有在之前返回代表当前区间并非包含于待查询区间,在向左右区间查询时需要先将懒标记下放
125     int mid = l + r >> 1;
126     if (L <= mid)
127         update(lson, L, R, v);
128     if (R > mid)
129         update(rson, L, R, v);
130     pushup(rt); //更新父区间
131 }
132 ll query(int rt, int L, int R)
133 {
134     int l = tr[rt].l;
135     int r = tr[rt].r;
136     if (l >= L && r <= R)
137         return tr[rt].sum;
138     pushdown(rt); //和update同理
139     int mid = l + r >> 1;
140     ll ans = 0;
141     if (L <= mid)
142         ans = max(ans, query(lson, L, R));
143     if (R > mid)
144         ans = max(ans, query(rson, L, R));
145     return ans;
146 }
147 int main(int argc, char const *argv[])
148 {
149 #ifndef ONLINE_JUDGE
150     freopen("in.txt", "r", stdin);
151     // freopen("out.txt", "w", stdout);
152 #endif
153     n = read<int>(), k = read<int>();
154     int maxx = 0;
155     for (int i = 0; i < n; i++)
156     {
157         int x = read<int>(), y = read<int>();
158         vec.emplace_back(x, y, i + 1);
159         maxx = max(maxx, y);
160     }
161     sort(vec.begin(), vec.end());
162     build(1, 1, maxx);
163     vector<int> res;
164     for (int i = 0; i < n; i++)
165     {
166         int cur = query(1, vec[i].l, vec[i].r);
167         if (cur < k)
168             update(1, vec[i].l, vec[i].r, 1);
169         else
170             res.emplace_back(vec[i].idx);
171     }
172     sort(res.begin(), res.end());
173     writeln(res.size());
174     for (int x : res)
175         write(x), pblank;
176     return 0;
177 }
View Code

E. By Elevator or Stairs?

Description

 Solution

简单dp

dp[i][0]表示走路到i层的最小花费,dp[i][1]表示电梯到i层的最小花费。

考虑状态转移

需要注意dp[2]是一开始就确定的,wa了一发

 1 #include <algorithm>
 2 #include <cctype>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <cstring>
 7 #include <iostream>
 8 #include <map>
 9 #include <queue>
10 #include <set>
11 #include <stack>
12 #if __cplusplus >= 201103L
13 #include <unordered_map>
14 #include <unordered_set>
15 #endif
16 #include <vector>
17 #define lson rt << 1, l, mid
18 #define rson rt << 1 | 1, mid + 1, r
19 #define LONG_LONG_MAX 9223372036854775807LL
20 #define ll LL
21 using namespace std;
22 typedef long long ll;
23 typedef long double ld;
24 typedef unsigned long long ull;
25 typedef pair<int, int> P;
26 int n, m, k;
27 const int maxn = 2e5 + 10;
28 template <class T>
29 inline T read()
30 {
31     int f = 1;
32     T ret = 0;
33     char ch = getchar();
34     while (!isdigit(ch))
35     {
36         if (ch == '-')
37             f = -1;
38         ch = getchar();
39     }
40     while (isdigit(ch))
41     {
42         ret = (ret << 1) + (ret << 3) + ch - '0';
43         ch = getchar();
44     }
45     ret *= f;
46     return ret;
47 }
48 template <class T>
49 inline void write(T n)
50 {
51     if (n < 0)
52     {
53         putchar('-');
54         n = -n;
55     }
56     if (n >= 10)
57     {
58         write(n / 10);
59     }
60     putchar(n % 10 + '0');
61 }
62 template <class T>
63 inline void writeln(const T &n)
64 {
65     write(n);
66     puts("");
67 }
68 ll dp[maxn][2];
69 ll a[maxn], b[maxn], c;
70 int main(int argc, char const *argv[])
71 {
72 #ifndef ONLINE_JUDGE
73     freopen("in.txt", "r", stdin);
74     freopen("out.txt", "w", stdout);
75 #endif
76     n = read<int>(), c = read<int>();
77     for (int i = 1; i < n; i++)
78         a[i] = read<ll>();
79     for (int i = 1; i < n; i++)
80         b[i] = read<ll>();
81     dp[2][1] = c + b[1];
82     dp[2][0] = a[1];
83     for (int i = 3; i <= n; i++)
84     {
85         dp[i][0] = min(dp[i - 1][1], dp[i - 1][0]) + a[i - 1];
86         dp[i][1] = min(dp[i - 1][0] + c, dp[i - 1][1]) + b[i - 1];
87     }
88     for (int i = 1; i <= n; i++)
89         write(min(dp[i][0], dp[i][1])), putchar(' ');
90     return 0;
91 }
View Code

F. Maximum Weight 

 

Description

给一棵n个结点的树,每条边权值为1,点权由题目给出。

求一个最大点集的点权和,要求点集里任意两结点的距离大于k。

solution

树形dp想了半天没想出来是个five没错了。

看到某聚聚用的逆序深度遍历求的结果。

大概是先dfs一遍求出每个点深度,然后从深度最大的叶子结点开始搜索。

每次加上当前选中的节点权值并将相邻k的节点的权值减去当前权值。

只要节点权值大于0则证明选择此节点比选择之前的更新过当前节点的权值的那些节点更加优秀,由于之前也在累加答案,且当前节点的权值已经是被减过的,只要在答案上加上当前权值就行了。重复步骤。(也有点像最优子结构)

为什么从叶子结点开始呢,我的理解是叶子结点在最外层,选择叶子结点能最大程度选择更多的点使得距离大于k,像是一种贪心思想。

原文地址:https://www.cnblogs.com/mooleetzi/p/11728001.html