CF Round 810 Div2 题解

比赛链接

A题 Perfect Permutation

给定正整数 n,要求构造出一个长度为 n 的排列 {pn},满足该排列的价值最小,并输出。

排列的价值:满足 i|pii 的个数。

T104,n,n105

学数论的时候,接触过一个性质:gcd(a1,a)=1(a>1)

那么,直接构造类似 (2,3,4,5,1) 的排列就行了。

#include<bits/stdc++.h> using namespace std; void solve() { int n; scanf("%d", &n); for (int i = 2; i <= n; ++i) printf("%d ", i); printf("1\n"); } int main() { int T; cin >> T; while (T--) solve(); return 0; }

B题 Party

已知有 n 个人,不邀请第 i 个人参加宴会的话,会增加 ai 的不满意度。

n 个人之间有 m 对关系,如果参加宴会的某两个人存在关系,那么他们就会很高兴,然后一起吃一块蛋糕。(一个人可以吃多个蛋糕,例如 1 和 2,3,4,5 都有关系,那么 1 就会吃 4 次蛋糕)。

不过,我们希望最后吃掉的蛋糕数量为偶数,问在此基础上,怎样使得不满意度最小?

T104,n,m,n,m105,0ai104

简化一下:给定一张 nm 边的点带权无向图,要求删除几个点(以及和它们相邻的边),使得剩下的图中,边的数量为偶数,在此基础上要求删除的点的点权和最小。

  1. m 为偶数时,不需要删除任何点,直接输出 0 即可

  2. m 为奇数时,我们统计图中的奇度点数量为 x,偶度点数量为 y

    1. x=0 时,我们需要删除一个偶度点,那么和他相连的所有点都变成了奇度点,挑一个最小的删除即可。

      因此,我们直接枚举要删哪两个点即可。显然,不存在其他更优的方案。

    2. x>0 时,我们可以采取上面的策略,也可以直接挑一个奇度点删掉。

总复杂度为 O(n+m)

#include<bits/stdc++.h> using namespace std; const int N = 100010; int n, m, a[N], u[N], v[N], d[N]; int solve() { scanf("%d%d", &n, &m); memset(d, 0, sizeof(int) * (n + 1)); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= m; ++i) { scanf("%d%d", &u[i], &v[i]); d[u[i]]++, d[v[i]]++; } if (m % 2 == 0) return 0; int ans = 1e9 + 10; for (int i = 1; i <= n; ++i) if (d[i] % 2 == 1) ans = min(ans, a[i]); for (int i = 1; i <= m; ++i) { int x = u[i], y = v[i]; if (d[x] % 2 == 0 && d[y] % 2 == 0) ans = min(ans, a[x] + a[y]); } return ans; } int main() { int T; cin >> T; while (T--) printf("%d\n", solve()); return 0; }

C题 Color the Picture

给定一个 nm 列的方格矩阵,初始状态下所有方格都没有颜色。

现在给定 k 种不同的颜料,但是第 i 种颜料至多能涂 ai 个方块。

问,能否找到一种涂色方式,使得所有方格都被涂上颜色,且任意一块的周围,至少三个方格的颜色和其相同?

“周围”的定义:如果两个方格的坐标分别为 (x1,y1),(x2,y2),且共享同一条边(具体定义可以参照原题面,简单来说,就是最上一列和最下一列,以及最左最右一列相邻)。

3n,m109,1ai109,k105

参照题目样例,发现:如果一个颜色要满足要求(且不妨碍他人),那么他应该单独占据连续的 2 行/列或者更多。(两个都要做一下,我这里就直接按照填列的方式来过一遍流程,跟样例的方式一样)

我们计算出每种颜料能够涂多少列,然后将大于等于 2 的找出来涂就行了。但是要注意,为了避免出现 2 2 2 2 1 这种情况,所以需要我们从小到大选颜料(排个序),如果发现涂完了后只剩一列,那么就自己少一列;如果自己只有两列,那么就跳过这个颜色,换下一个来涂。最终根据涂色状况来判断能不能达成目标,复杂度 O(klogk)

#include<bits/stdc++.h> using namespace std; const int N = 100010; int n, m, k, a[N]; bool check(int n, int m) { int cnt = m; for (int i = 1; i <= k; i++) { int t = a[i] / n; if (t < 2) continue; if (cnt <= t) return true; else if (cnt - t == 1) { if (t == 2) continue; else cnt = 2; } else cnt -= t; } return false; } bool solve() { scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= k; ++i) scanf("%d", &a[i]); sort(a + 1, a + k + 1); if (check(n, m)) return true; return check(m, n); } int main() { int T; cin >> T; while (T--) puts(solve() ? "YES" : "NO"); return 0; }

__EOF__

本文作者cyhforlight
本文链接https://www.cnblogs.com/cyhforlight/p/16518846.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cyhforlight  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示