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 }
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 }
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 }
D1. Too Many Segments
Description
Solution
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 }
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 }
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 }
F. Maximum Weight
Description
给一棵n个结点的树,每条边权值为1,点权由题目给出。
求一个最大点集的点权和,要求点集里任意两结点的距离大于k。
solution
树形dp想了半天没想出来是个five没错了。
看到某聚聚用的逆序深度遍历求的结果。大概是先dfs一遍求出每个点深度,然后从深度最大的叶子结点开始搜索。
每次加上当前选中的节点权值并将相邻k的节点的权值减去当前权值。
只要节点权值大于0则证明选择此节点比选择之前的更新过当前节点的权值的那些节点更加优秀,由于之前也在累加答案,且当前节点的权值已经是被减过的,只要在答案上加上当前权值就行了。重复步骤。(也有点像最优子结构)
为什么从叶子结点开始呢,我的理解是叶子结点在最外层,选择叶子结点能最大程度选择更多的点使得距离大于k,像是一种贪心思想。