【解题报告】Codeforces Round #303 (Div. 2)
来源:互联网 发布:会计应对大数据时代 编辑:程序博客网 时间:2024/06/06 16:48
题目链接
A.Toy Cars(Codeforces 545A)
思路
简单实现题。将表示碰撞结果的矩阵保存下来,然后检查每个车辆是否是“good car“即可。
代码
#include <bits/stdc++.h>using namespace std;const int maxn = 110;bool good;int n, G[maxn][maxn];vector <int> v;int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { scanf("%d", &G[i][j]); } good = true; for(int j = 1; j <= n; j++) { if(i != j && G[i][j] % 2) { good = false; } } if(good) v.push_back(i); } printf("%d\n", v.size()); for(int i = 0; i < v.size(); i++) { printf("%d ", v[i]); } puts(""); return 0;}
B.Equidistant String(Codeforces 545B)
思路
要构造一个与两个输入字符串的汉明距离都相等的字符串,只要从一个字符串出发“走过”两个字符串汉明距离的一半就可以了。具体地,假设输入的串为
代码
#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 5;char s[maxn], t[maxn];int n, m, cnt;vector <int> v;int main() { scanf("%s%s", s, t); cnt = 0; n = strlen(s); for(int i = 0; i < n; i++) { if(s[i] != t[i]) { v.push_back(i); cnt++; } } if(cnt % 2) puts("impossible"); else { m = cnt >> 1; for(int i = 0; i < m; i++) { s[v[i]] = t[v[i]]; } printf("%s\n", s); } return 0;}
C.Woodcutters(Codeforces 545C)
大意
在一条数轴上有若干棵树。每棵树有一个高度,问最多能砍多少棵树,使得没有倒下的树碰到其它的树。
思路
这题最直观的解法是搜索。搜索树的每一层都表示一次决策,即该层表示的树是往左倒还是往右倒。但由于
- 第i棵树直立的时候。不论第
i 棵想要直立是可以“不看前一棵树的脸色”的,因此有d[i][0]=max{d[i−1][j],0≤j≤2} 。 - 第i棵树向左倒的时候。第i棵树想要向左倒,就必须“看前一棵树的脸色”,也就是看前一棵树给它留下了多少空位。当前一棵树没有向右倒的时候有
d[i][1]=max(d[i−1][0],d[i−1][1])+1 ,当前一棵树向右倒的时候有d[i][1]=max(d[i][1],d[i−1][2]+1) 。在实现的时候要注意判断位置是否足够让一棵树倒下。 - 第i棵树向右倒的时候。这种情况的最优值一定比第
i 棵树直立的时候要多1 ,因此d[i][2]=d[i][0]+1 。
最后的答案就是
代码
#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 10, INF = 1e9;int n, ans, x[maxn], h[maxn], d[maxn][3];int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d%d", &x[i], &h[i]); } // 设置两棵虚拟的树 x[0] = - INF; x[n+1] = INT_MAX; for(int i = 1; i <= n; i++) { // 直立 d[i][0] = max(max(d[i-1][0], d[i-1][1]), d[i-1][2]); // 向左倒 if(h[i] < x[i] - x[i-1]) { d[i][1] = max(d[i-1][0], d[i-1][1]) + 1; } if(h[i] + h[i-1] < x[i] - x[i-1]) { d[i][1] = max(d[i][1], d[i-1][2] + 1); } // 向右倒 if(h[i] < x[i+1] - x[i]) { d[i][2] = d[i][0] + 1; } } printf("%d\n", d[n][2]); return 0;}
思路
其实本题也不是没有贪心策略。对于两端的树而言,左端的树往左倒,右端的树往右倒一定是最优的策略。对于其它的树(从左向右扫描的话),先考虑向左倒再考虑向右倒一定是最优策略。(证明方法暂时没想到)
代码
#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 10;int n, ans, x[maxn], h[maxn];int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d%d", &x[i], &h[i]); } ans = 2; for(int i = 2; i < n; i++) { if(x[i] - x[i-1] > h[i]) { ans++; } else if(x[i+1] - x[i] > h[i]) { x[i] += h[i]; ans++; } } printf("%d\n", n <= 2 ? n : ans); return 0;}
D.Queue(Codeforces 545D)
大意
有若干个人在排队等待服务,服务员服务每个人的时间都是不同的,对于一个人而言,若他前面的人的被服务总时间大于它自己被服务的时间,他就会感到失望。问最多可以让多少人感到不失望。
思路
拿到这道题,直觉告诉我应该是先对数据排序(因为感性认知告诉我忍耐值小的人放在前面似乎能够满足尽可能多的人)然后再微调(感性认知不一定是事实)。为了方便讨论我们用O表示排好序的队列中不会失望的某个人,用X表示排好序的队列中会失望的某个人。在微调的过程中,首先
所以我们总结出算法:先对输入数据排序,然后扫描排序后数据的同时维护前缀和
代码
#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 10;int n, cnt, sum, a[maxn];int main() { scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%d", &a[i]); } sort(a, a + n); cnt = sum = 0; for(int i = 0; i < n; i++) { if(a[i] >= sum) { sum += a[i]; cnt++; } } printf("%d\n", cnt); return 0;}
E.Paths and Trees(Codefoeces 545E)
大意
在一个图
思路
这个问题同时具有最小生成树和最短路径的特点,但最小生成树无法算出起点到每个点的最短路径,因此只考虑用后者来解决问题。
假设我们已经在原图上跑了一遍
最后,在算法的实现上,我们需要跑一遍修改后的
代码
#include <bits/stdc++.h>using namespace std;typedef long long ll;// 优先队列用的结点typedef pair <ll, int> p;const int maxn = 3e5 + 10;const ll INF = 1e15;int n, m, u, v;ll w, sum;vector <int> ans;// 存储边的信息的结构体struct edge { int from, to; ll dist; edge(int from, int to, ll dist): from(from), to(to), dist(dist) {}};// Dijkstra算法模板struct Dijkstra { // 保存最短路径距离 ll d[maxn]; // 保存点的前驱边 int f[maxn]; // 保存边集 vector <edge> edges; // 邻接表 vector <int> G[maxn]; // 将一条边加入邻接表 void addEdge(int u, int v, ll w) { G[u].push_back(edges.size()); edges.push_back(edge(u, v, w)); } void solve(int s) { // 初始化最短路径距离数组 fill(d + 1, d + n + 1, INF); d[s] = 0; // 初始化优先队列 priority_queue < p, vector<p>, greater<p> > pq; pq.push(p(0, s)); while(!pq.empty()) { p node = pq.top(); pq.pop(); int u = node.second; if(node.first > d[u]) { continue; } for(int i = 0; i < G[u].size(); i++) { edge& e = edges[G[u][i]]; int v = e.to; // 松弛的同时更新前驱边 if(d[v] > d[u] + e.dist) { d[v] = d[u] + e.dist; f[v] = G[u][i]; pq.push(p(d[v], v)); } // 修改前驱边 if(d[v] == d[u] + e.dist && e.dist < edges[f[v]].dist) { f[v] = G[u][i]; } } } }}o;int main() { scanf("%d%d", &n, &m); while(m--) { scanf("%d%d%I64d", &u, &v, &w); o.addEdge(u, v, w); o.addEdge(v, u, w); } scanf("%d", &u); o.solve(u); sum = 0; for(int i = 1; i <= n; i++) { if(i == u) { continue; } sum += o.edges[o.f[i]].dist; ans.push_back(o.f[i] / 2 + 1); } printf("%I64d\n", sum); for(int i = 0; i < ans.size(); i++) { printf("%d ", ans[i]); } return 0;}
- 【解题报告】Codeforces Round #303 (Div. 2)
- Codeforces Round #149 (Div. 2)解题报告
- Codeforces Round #180 (Div. 2) 解题报告
- Codeforces Round #190 (Div. 2) 解题报告
- Codeforces Round #191 (Div. 2) 解题报告
- Codeforces Round #189 (Div. 2) 解题报告
- Codeforces Round #142 (Div. 2) 解题报告
- Codeforces Round #229 (Div. 2) 解题报告
- Codeforces Round #241 (Div. 2) 解题报告
- Codeforces Round #262 (Div. 2)解题报告
- Codeforces Round #267 (Div. 2) 解题报告
- Codeforces Round #266 (Div. 2)解题报告
- Codeforces Round #268 (Div. 2) 解题报告
- Codeforces Round #271 (Div. 2) 解题报告
- Codeforces Round #274 (Div. 2) 解题报告
- Codeforces Round #276 (Div. 2) 解题报告
- Codeforces Round #277 (Div. 2) 解题报告
- Codeforces Round #224 (Div. 2)解题报告
- Codeforces 659E 找环+(并查集/dfs)
- Java实现二叉树
- C++作业2:银行
- sublime text在ubuntu平台下的中文输入问题及解决
- Flex+BlazeDS+IntelliJ IDEA整合开发系列一之起步demo
- 【解题报告】Codeforces Round #303 (Div. 2)
- 08-maven同时下载源码
- 解决安卓TextView高度和textSize大小不一致问题 - 木杉是天才
- [BZOJ2461][BeiJing2011]符环(记忆化搜索)
- LeetCode之4---Median of Two Sorted Arrays
- 把自己电脑变成FTP服务器~~
- 【C++ Primer plus】【第九章】内存模型和名称空间
- 实现无锁的栈与队列
- Eclipse环境下配置spket中ExtJS提示(针对无提示和提示错误)