AtCoder Regular Contest 063题解
2016-11-08 16:29
417 查看
链接:AtCoder Regular Contest 063
C. 一次元リバーシ
一道大水题,统计有多少颜色不同的段减1就好了。复杂度O(n)。#include<bits/stdc++.h> const int N = 100010; char s ; int main() { scanf("%s", s); int cnt = 0, len = strlen(s); for (int i = 1; i < len; i++) if (s[i] != s[i - 1]) cnt ++; printf("%d\n", cnt); return 0; }
D. 高橋君と見えざる手
第二道大水题。容易知道,高桥会选择差价最大的两个城市来买卖苹果(当然,只能在前面的城市买进,在后面的城市卖出)。于是青木就只需要把每对差价等于最大差价的城市修改1就好了。本来这道题还需要讨论很多,但是都被输入限制住了。。复杂度O(n)#include<bits/stdc++.h> const int N = 100010; int n, t, a , max ; int main() { scanf("%d%d", &n, &t); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); for (int i = n; i; i --) { max[i] = max[i + 1]; if (a[i] > max[i]) max[i] = a[i]; } for (int i = 1; i <= n; i ++) a[i] = max[i] - a[i]; int ans = 0; for (int i = 1; i <= n; i ++) if (ans < a[i]) ans = a[i]; int cnt = 0; for (int i = 1; i <= n; i ++) if (a[i] == ans) cnt ++; return printf("%d\n", cnt), 0; }
E. 木と整数
任取一个已经填了数的结点作为根结点。首先,我们可以确定每一个结点的奇偶性,如有矛盾退出程序。之后我们从叶子结点开始回溯,对于叶子结点,若没有填数字,区间置为[−∞,∞],若填了数a,则置为[a,a]。对于非叶子结点,区间置为⋂i是该结点的孩子[xi,yi],若这个结点已经填了数a,则要先判断是否产生了矛盾,若无矛盾则置为[a,a]。如果回溯到根结点仍然没有矛盾,说明存在可行解。从根结点开始填数,只要注意与父亲结点差1,并且在范围内,一定能满足题目要求。复杂度O(n)。#include<bits/stdc++.h> using namespace std; const int N = 100010; struct point { int num, first, left, right; bool visited, odd; }; struct edge { int next, to; }; int cnt = 1, n, k; edge e[N << 1]; point p ; void addedge(int u, int v) { e[++ cnt].next = p[u].first; p[u].first = cnt; e[cnt].to = v; e[++ cnt].next = p[v].first; p[v].first = cnt; e[cnt].to = u; } void dfs1(int i) { p[i].visited = true; if (~p[i].num && p[i].odd != (p[i].num & 1)) { printf("No\n"); exit(0); } for (int j = p[i].first; j; j = e[j].next) { int x = e[j].to; if (p[x].visited) continue; p[x].odd = !p[i].odd; dfs1(x); p[i].left = max(p[i].left, p[x].left - 1); p[i].right = min(p[i].right, p[x].right + 1); } if (p[i].left > p[i].right) { printf("No\n"); exit(0); } } void dfs2(int i) { p[i].visited = true; for (int j = p[i].first; j; j = e[j].next) { int x = e[j].to; if (p[x].visited) continue; if (p[i].num - 1 >= p[x].left && p[i].num - 1 <= p[x].right) p[x].num = p[i].num - 1; else p[x].num = p[i].num + 1; dfs2(x); } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++) { p[i].num = -1; p[i].left = -1e9; p[i].right = 1e9; } for (int i = 0, u, v; i < n - 1; i ++) { scanf("%d%d", &u, &v); addedge(u, v); } scanf("%d", &k); int root; for (int i = 0, x, num; i < k; i ++) { scanf("%d%d", &x, &num); p[x].num = num; p[x].left = num; p[x].right = num; root = x; } p[root].odd = p[root].num & 1; dfs1(root); for (int i = 1; i <= n; i ++) p[i].visited = false; dfs2(root); printf("Yes\n"); for (int i = 1; i <= n; i ++) printf("%d\n", p[i].num); return 0; }
F. すぬけ君の塗り絵 2
首先,容易证明答案大于2max(W,H)+2:取x坐标相邻的两点,左边的点全部向左涂黑,右边的点全部向右涂黑,得到的周长最小为2H+2,同理对y坐标,周长最小为2W+2。这样我们就有了一个结论:所得的矩形至少与x=W2和y=H2两条直线之一相交(用反证法易证)。下面,不妨设矩形与x=W2相交。也就是说,在x=W2左边的点,只能向左、上、下三个方向涂色,右边的点只能向右、上、下三个方向涂色。那么,如果我们再固定最终答案的上边界和下边界,那么每个点的涂色方向都确定了:上边界以上的点向上涂色,下边界以下的点向下涂色,上下边界之间的点,在x=W2左边的向左涂色,右边的向右涂色。但是,如果直接两两枚举,显然会超时,这时候我们就需要一些优化。我们用一个线段树来维护,按y坐标从小到大枚举每个点,对于每个y坐标小于它的结点,我们记录,以当前枚举到的结点为上边界,以y小的结点为下边界,按照上面所说的涂法,得到的白色矩形的长(沿x轴方向)减去y小的结点的y坐标。这样,这个矩形的周长就是记录的这个值,加上当前枚举的结点的y坐标,再乘以2。显然,对于我们枚举的每个结点,其为上边界时的最大周长,就是所有记录的值中的最大值加上其y坐标乘以2。那么我们就在线段树中维护这些记录的最大值。接下来我们考虑一下如何更新线段树:每次枚举完一个点后,我们就要更新之前所有的点,这样显然会超时。那么我们看一下哪些点需要被更新。不妨只考虑x≤W2的点,如果该点的坐标x1小于刚被枚举的点x2,那么这个点为下界时长的值就要减去x2−x1,同时我们注意到,更新完之后,该点的长的值已经和刚枚举完的结点一样了,也就是说,我们以后碰到一个横坐标更大的点再来更新时,这两个点减去的值是一样的。所以,我们可以用一个栈来记录未被更新过的结点,已被更新过的结点则一定和最近的y坐标更大且未被更新过的结点值相同,这样我们就可以修改区间来修改线段树的值了。显然,每个点只进出栈一次。x>W2时的情况也类似。然后对于与y=H2相交的情况再同样地讨论即可(具体实现时可以直接把整个图关于y=x对称一下)。复杂度O(nlogn)。#include<bits/stdc++.h> const int INF = 1e9; const int N = 300010; const int MAX = 19; using namespace std; struct segment{ int lazy, rmax; }; int w, h, n, x , y ; segment seg[1 << MAX + 1]; vector <pair <int, int>> p; vector <int>_y; stack <pair <int, int>> ls, rs; int ysit(int y){ return lower_bound(_y.begin(), _y.end(), y) - _y.begin(); } void build(){ for (int i = 1 << MAX; i < (1 << MAX) + _y.size(); i ++) seg[i].rmax = w - _y[i - (1 << MAX)]; for (int i = (1 << MAX) + _y.size(); i < 1 << MAX + 1; i ++) seg[i].rmax = -INF; for (int i = (1 << MAX) - 1; i; i --) seg[i].rmax = max(seg[i << 1].rmax, seg[(i << 1) + 1].rmax); } void add(int left, int right, int point, int depth, int v){ int l = point << depth, r = point + 1 << depth; if (depth){ seg[point << 1].rmax += seg[point].lazy; seg[point << 1].lazy += seg[point].lazy; seg[(point << 1) + 1].rmax += seg[point].lazy; seg[(point << 1) + 1].lazy += seg[point].lazy; } seg[point].lazy = 0; if (l == left && r == right + 1){ seg[point].rmax += v; seg[point].lazy += v; return; } int mid = l + r >> 1; if (right < mid) add(left, right, point << 1, depth - 1, v); else if (left >= mid) add(left, right, (point << 1) + 1, depth - 1, v); else{ add(left, mid - 1, point << 1, depth - 1, v); add(mid, right, (point << 1) + 1, depth - 1, v); } seg[point].rmax = max(seg[point << 1].rmax, seg[(point << 1) + 1].rmax); } void add(int left, int right, int v){ if (left > right) return; add(left + (1 << MAX), right + (1 << MAX), 1, MAX, v); } int query(int left, int right, int point, int depth){ int l = point << depth, r = point + 1 << depth; if (depth){ seg[point << 1].rmax += seg[point].lazy; seg[point << 1].lazy += seg[point].lazy; seg[(point << 1) + 1].rmax += seg[point].lazy; seg[(point << 1) + 1].lazy += seg[point].lazy; } seg[point].lazy = 0; if (l == left && r == right + 1) return seg[point].rmax; int mid = l + r >> 1, ret = -INF; if (right < mid) return query(left, right, point << 1, depth - 1); if (left >= mid) return query(left, right, (point << 1) + 1, depth - 1); ret = max(ret, query(left, mid - 1, point << 1, depth - 1)); ret = max(ret, query(mid, right, (point << 1) + 1, depth - 1)); return ret; } int query(int left, int right){ if (left > right) return -INF; return query(left + (1 << MAX), right + (1 << MAX), 1, MAX); } int solve(){ memset(seg, 0, sizeof(seg)); p.clear(); _y.clear(); while (!ls.empty()) ls.pop(); while (!rs.empty()) rs.pop(); ls.push({0, w / 2}); rs.push({0, w / 2}); for (int i = 0; i < n; i ++) p.push_back({y[i], x[i]}); sort(p.begin(), p.end()); p.push_back({h, 0}); for (int i = 0; i < n; i ++) _y.push_back(y[i]); _y.push_back(0); _y.push_back(h); sort(_y.begin(), _y.end()); _y.erase(unique(_y.begin(), _y.end()), _y.end()); build(); int ret = 0; for (int i = 0; i < p.size(); i ++){ int X = p[i].second, Y = p[i].first; ret = max(ret, query(0, ysit(Y) - 1) + Y); if (X <= w / 2){ int lastx = 0, lasty = Y; while (!ls.empty() && ls.top().second < X){ add(ysit(ls.top().first), ysit(lasty) - 1, lastx - X); lastx = ls.top().second; lasty = ls.top().first; ls.pop(); } add(ysit(ls.top().first), ysit(lasty) - 1, lastx - X); ls.push({Y, X}); } else{ int lastx = w, lasty = Y; while (!rs.empty() && rs.top().second > X){ add(ysit(rs.top().first), ysit(lasty) - 1, X - lastx); lastx = rs.top().second; lasty = rs.top().first; rs.pop(); } add(ysit(rs.top().first), ysit(lasty) - 1, X - lastx); rs.push({Y, X}); } } return ret; } int main() { scanf("%d%d%d", &w, &h, &n); w *= 2; h *= 2; for (int i = 0; i < n; i ++){ scanf("%d%d", &x[i], &y[i]); x[i] *= 2; y[i] *= 2; } int ans = solve(); swap(w, h); for (int i = 0; i < n; i ++) swap(x[i], y[i]); ans = max(ans, solve()); return printf("%d\n", ans), 0; }
相关文章推荐
- AtCoder Regular Contest 063 Integers on a Tree 树形dp+构造
- AtCoder Regular Contest 078
- AtCoder Regular Contest 082
- atcoder AtCoder Regular Contest 084 D - Small Multiple 最短路
- AtCoder Regular Contest 077 E - guruguru
- AtCoder Regular Contest 090 D People on a Line
- AtCoder Regular Contest 089 D - Checker 思维题、点的转移、二维前缀和
- AtCoder Regular Contest 092 B Two Sequences
- 【搜索】[AtCoder Regular Contest 092 F]Two Faced Edges
- AtCoder Regular Contest 093 D - Grid Components
- AtCoder Beginner Contest 063
- AtCoder AtCoder Beginner Contest 063 D - Widespread(二分)
- AtCoder Regular Contest 075 E - Meaningful Mean(树状数组)
- AtCoder Regular Contest 076E Coneected?
- AtCoder Regular Contest 090
- AtCoder Regular Contest 080 F - Prime Flip 线性筛+匈牙利算法
- AtCoder Regular Contest 077 E - guruguru 二阶差分
- [AtCoder Regular Contest 077] F: SS (arc077F)
- AtCoder Regular Contest 093 D - Grid Components
- *AtCoder Regular Contest 094 F - Normalization