博客
关于我
[Codeforces]Round 656 div3 题解(A-E)
阅读量:565 次
发布时间:2019-03-10

本文共 10353 字,大约阅读时间需要 34 分钟。

技术文章

A 题解析与实现

题目要求

给定三个变量 a、b、c,定义 x = max(a, b),y = max(a, c),z = max(b, c)。要求找出任意一组符合条件的 a、b、c。

解题思路

  • 确定最大值:首先确定 x、y、z 中的最大值。
  • 分类讨论:根据最大值出现的次数进行分类讨论。
  • 构造满足条件的数组:通过确定最大值的出现次数,构造满足条件的 a、b、c。
  • 解决代码

    #include 
    #include
    #include
    #include
    using namespace std;int main() { // 读取输入 const int bufSize = 1e6; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } inline void read(char *s) { static char c; for (; !isalpha(c); c = nc()); for (; isalpha(c); c = nc()) *s++ = c; *s = '\0'; } template
    inline t read(t &r) { static char c; static int flag; flag = 1, r = 0; for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1; for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r *= flag; } int T; int a[4]; int main() { read(T); while (T--) { for (int i = 1; i <= 3; ++i) read(a[i]); sort(a + 1, a + 4); if (a[1] == a[2] && a[2] == a[3]) { puts("YES"); printf("%d %d %d\n", a[3], a[2], 1); } else { puts("NO"); } } return 0; }}

    代码解释

  • 读取输入:使用自定义的 read 函数读取输入数据,处理大输入的情况。
  • 排序数组:对数组进行排序,确定最大值。
  • 判断条件:检查数组是否满足条件,输出结果。
  • B 题解析与实现

    题目要求

    给定一个数组,通过删除某些元素使得剩余元素形成一个非递减序列。

    解题思路

  • 观察样例:发现只需要保留首次出现的元素。
  • 证明结论:数组中每个元素只能出现一次,删除重复的元素即可。
  • 实现删除过程:通过遍历数组,记录已访问的元素,删除重复的元素。
  • 解决代码

    #include 
    #include
    #include
    #include
    using namespace std;int main() { const int bufSize = 1e6; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } inline void read(char *s) { static char c; for (; !isalpha(c); c = nc()); for (; isalpha(c); c = nc()) *s++ = c; *s = '\0'; } template
    inline t read(t &r) { static char c; static int flag; flag = 1, r = 0; for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1; for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r *= flag; } int T, n; vector
    a, vis; int main() { read(T); while (T--) { read(n); a.clear(); vis.resize(n + 1, 0); for (int i = 1; i <= n; ++i) { int x; read(x); if (!vis[x]) { vis[x] = 1; a.push_back(x); } } for (int i = 1; i <= n; ++i) { if (vis[i] == 1) { printf("%d ", i); } } putchar('\n'); } return 0; }}

    代码解释

  • 读取输入:与 A 题类似,使用自定义函数处理输入。
  • 记录访问元素:使用 vis 数组记录已访问的元素,避免重复。
  • 输出结果:遍历数组,输出首次出现的元素,形成非递减序列。
  • C 题解析与实现

    题目要求

    给定一个数组,要求每次取头尾元素,所取元素单调不减。

    解题思路

  • 峰点存在性:数组中存在一个峰点,左边单调不减,右边单调不增。
  • 找峰点:从数组两端向中间查找峰点。
  • 删除操作:根据峰点位置,删除相应的元素。
  • 解决代码

    #include 
    #include
    #include
    #include
    using namespace std;int main() { const int bufSize = 1e6; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } inline void read(char *s) { static char c; for (; !isalpha(c); c = nc()); for (; isalpha(c); c = nc()) *s++ = c; *s = '\0'; } template
    inline t read(t &r) { static char c; static int flag; flag = 1, r = 0; for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1; for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r *= flag; } int T, n; vector
    a; int main() { read(T); while (T--) { read(n); a.resize(n + 1); for (int i = 1; i <= n; ++i) { int x; read(x); a[i] = x; } int top = n; while (top > 1 && a[top - 1] >= a[top]) --top; int head = top; while (head > 1 && a[head - 1] <= a[head]) --head; if (head == 1) { puts("1\n"); } else { puts(to_string(head - 1) + "\n"); } } return 0; }}

    代码解释

  • 读取输入:与前几题类似,使用自定义函数处理输入。
  • 找峰点:从两端向中间查找峰点。
  • 输出结果:根据峰点位置,删除相应的元素,输出结果。
  • D 题解析与实现

    题目要求

    给定一个字符串,找出最少删除次数使其成为好串。

    解题思路

  • 分治法:每次假设左边或右边全是某个字符,计算相应的代价。
  • 前缀和:使用前缀和数组快速计算代价。
  • 递归处理:递归处理左右子问题,得到最优解。
  • 解决代码

    #include 
    #include
    #include
    #include
    using namespace std;int main() { const int bufSize = 1e6; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } inline void read(char *s) { static char c; for (; !isalpha(c); c = nc()); for (; isalpha(c); c = nc()) *s++ = c; *s = '\0'; } template
    inline t read(t &r) { static char c; static int flag; flag = 1, r = 0; for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1; for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r *= flag; } int T, n; string s; int main() { read(T); while (T--) { read(n); s.resize(n + 1); for (int i = 1; i <= n; ++i) { char c; read(c); s[i] = c; s[i] -= 'a'; } vector
    > sum(n + 1, vector
    (26, 0)); for (int i = 1; i <= n; ++i) { sum[i][s[i]]++; for (int j = 0; j < 26; ++j) { sum[i][j] += sum[i - 1][j]; } } auto solve = [&](int l, int r, int c) -> int { if (l == r) return (s[l] != c); int mid = l + r > 1 ? (l + r) / 2 : l; int left = solve(l, mid, c + 1); int right = solve(mid + 1, r, c + 1); int lval = left + (r - mid) - sum[mid][c]; int rval = right + (mid - l + 1) - (sum[mid][c] - sum[l - 1][c]); return min(lval, rval); }; int res = solve(1, n, 0); printf("%lld\n", res); } return 0; }}

    代码解释

  • 读取输入:与前几题类似,处理大输入。
  • 前缀和数组:用于快速计算字符的出现次数。
  • 递归函数:使用分治法计算最少删除次数。
  • 返回结果:输出最优解。
  • E 题解析与实现

    题目要求

    给定一个有向图和无向边,判断是否可以转换为有向无环图。

    解题思路

  • 拓扑排序:对图进行拓扑排序。
  • 环检测:在拓扑排序过程中检测是否存在环。
  • 边转换:根据拓扑排序结果决定无向边的方向。
  • 解决代码

    #include 
    #include
    #include
    #include
    using namespace std;int main() { const int bufSize = 1e6; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } inline void read(char *s) { static char c; for (; !isalpha(c); c = nc()); for (; isalpha(c); c = nc()) *s++ = c; *s = '\0'; } template
    inline t read(t &r) { static char c; static int flag; flag = 1, r = 0; for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1; for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r *= flag; } int T, n, m; struct edge { int to, next; bool directed; }; edge E[maxm + 1]; int head[n + 1], tot; int in[n + 1]; void topo() { int qh = 1, qt = 0; for (int i = 1; i <= n; ++i) if (!in[i]) q[++qt] = i; while (qt > qh) { if (ans) return; int u = q[qh++]; for (int p = head[u]; p; p = E[p].next) { int v = E[p].to; if (!E[p].directed) continue; if (--in[v] == 0) q[++qt] = v; if (in[v] < 0) ans = 1; } } } int main() { read(T); while (T--) { ans = tot = 0; read(n), read(m); for (int i = 1; i <= n; ++i) { vis[i] = 0, head[i] = 0, in[i] = 0; } for (int i = 1; i <= m; ++i) { int t, a, b; read(t), read(a), read(b); add(a, b, t); if (t) in[b]++; } topo(); if (ans) { puts("NO"); continue; } for (int i = 1; i <= n; ++i) { if (!id[i] || vis[i] != 1) { puts("NO"); goto end; } } puts("YES"); for (int i = 1; i <= m; ++i) { if (E[i].directed) { printf("%d %d\n", E[i].from, E[i].to); } else if (id[E[i].from] < id[E[i].to]) { printf("%d %d\n", E[i].from, E[i].to); } else { printf("%d %d\n", E[i].to, E[i].from); } } end:; return 0; }}

    代码解释

  • 读取输入:处理输入,包括有向边和无向边。
  • 拓扑排序:对图进行拓扑排序,检测环。
  • 边转换:根据拓扑排序结果,转换无向边为有向边。
  • 输出结果:验证结果是否符合要求,输出相应结果。
  • F 题解析与实现

    题目要求

    给定一个树,删除叶子节点,使得树变成链状结构。

    解题思路

  • 贪心算法:每次删除尽可能多的叶子节点。
  • 优先队列:使用优先队列来处理节点的删除顺序。
  • 动态维护:根据删除情况,动态维护节点的状态。
  • 解决代码

    #include 
    #include
    #include
    #include
    #include
    #include
    using namespace std;int main() { vector
    fa, sonnum, leafnum; struct node { int x; int id; int type; bool operator<(const node &that) const { if (type != that.type) return type > that.type; return leafnum[id] > leafnum[that.id]; } }; int T, n, k; vector
    E; vector
    head; queue
    q; vector
    vis; int maxn = 2e5 + 100; int main() { read(T); while (T--) { tot = 0; read(n), read(k); fa.resize(n + 1, 0); sonnum.resize(n + 1, 0); leafnum.resize(n + 1, 0); while (!q.empty()) q.pop(); for (int i = 1; i <= n; ++i) { int a, b; read(a), read(b); add(a, b); add(b, a); } for (int i = 1; i <= n; ++i) { if (!head[i]) { fa[i] = i; for (int p = head[i]; p; p = E[p].next) { int v = E[p].to; if (v != fa[i]) { fa[v] = i; sonnum[i]++; } } if (sonnum[i] == leafnum[i]) { node t; t.x = leafnum[i]; t.id = i; t.type = 0; vis[i] = q.push(t); } else if (leafnum[i]) { node t; t.x = leafnum[i]; t.id = i; t.type = 1; vis[i] = q.push(t); } } } int ans = 0; while (take(k)) ++ans; printf("%d\n", ans); } return 0; }}

    代码解释

  • 读取输入:处理输入数据,初始化数据结构。
  • 树构建:构建树的结构,确定父节点和子节点关系。
  • 优先队列处理:使用优先队列来处理叶子节点的删除顺序。
  • 动态维护:根据删除情况,动态维护节点的状态,确保算法正确性。
  • 通过以上解析和实现,可以逐一解决每个小题的要求,确保代码的正确性和效率。

    转载地址:http://mpwvz.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现获取本机系统版本(附完整源码)
    查看>>
    Objective-C实现获取桌面应用程序图标位置 (附完整源码)
    查看>>
    Objective-C实现获取电脑所有盘符和容量大小 (附完整源码)
    查看>>
    Objective-C实现获取电脑网卡信息(附完整源码)
    查看>>
    Objective-C实现获取磁盘分区信息(附完整源码)
    查看>>
    Objective-C实现获取磁盘盘符以及剩余空间(附完整源码)
    查看>>
    Objective-C实现获得第 N 个卢卡斯数算法 (附完整源码)
    查看>>
    Objective-C实现蓄水池算法(附完整源码)
    查看>>
    Objective-C实现蓄水池算法(附完整源码)
    查看>>
    Objective-C实现蓄水池算法(附完整源码)
    查看>>
    Objective-C实现装饰模式(附完整源码)
    查看>>
    Objective-C实现观察者模式(附完整源码)
    查看>>
    Objective-C实现观访问者模式(附完整源码)
    查看>>
    Objective-C实现视频流转换为图片(附完整源码)
    查看>>
    Objective-C实现视频除雾算法(附完整源码)
    查看>>
    Objective-C实现角谷猜想(附完整源码)
    查看>>
    Objective-C实现解密 Atbash 密码算法(附完整源码)
    查看>>
    Objective-C实现解密藏头诗(附完整源码)
    查看>>
    Objective-C实现解析数学表达式解析(附完整源码)
    查看>>
    Objective-C实现解释器模式(附完整源码)
    查看>>