Codeforces Round 876 (Div. 2) 题解 A - D

A. The Good Array

题目大意

给定两个整数 nk,规定一个01数列为好的的条件是,对于1n中任意的 i,都有:

  • a 的前 i 个元素中至少有 ik 个都是 1
  • a 的后 i 个元素中至少有 ik 个都是 1

问数列中 1 的数量的最小可能值。

解题思路

先考虑最简单的情况,k 取得 1,这样我们的每一个元素都必须为 1

如果 k 不是 1,我们最终得到的序列一定是把 1 公摊使用的,那么前 k 个元素当中,只需要第一个元素是 1 即可,由前后缀的限制我们的数列也一定是对称的,依次类推,我们不难看出,实际上所求的数就是 n+k1k1

AC Code

#include <iostream> #include <algorithm> #include <cstring> #include <iomanip> #include <cmath> #define endl '\n' #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr) using namespace std; typedef long long LL; const int N = 1e5 + 10; const int MOD = 1e9 + 7; void solve() { double n, k; cin >> n >> k; if (k == 1) { cout << n << endl; return; } cout << ceil((n + k - 1) / k) << endl; } signed main() { ios; int T = 1; cin >> T; while (T--) { solve(); } }

B. Lamps

题目大意

每个灯有打开,关闭和坏掉三种状态,以及两个参数 ab。其中, b 代表打开一盏灯的得点。a 代表一种制约关系,当场上打开了 x 盏灯,那么场上所有 a 值小于 x 的灯会同时坏掉,不可以再次操作。

问最后最大得点为多少。

解题思路

首先我们来看看最优情况是怎么样的。

如果存在一个 a 值很小,比方说是 1,然后 b 值很大的一盏灯,那么我们肯定会优先开启这盏灯,然后它会坏掉,同时保留这盏灯的得点。

那么我们可以对这些灯按照 a 值分类,在每一类中对 b 值由大到小排序,随后只需要暴力找每个值即可。

AC Code

#include <iostream> #include <algorithm> #include <cstring> #define endl '\n' #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr) using namespace std; typedef long long LL; const int N = 2e5 + 10; const int MOD = 1e9 + 7; void solve() { int n; LL res = 0; cin >> n; vector<vector<int>> v(n + 1); for (int i = 1; i <= n; ++i) { int x, y; cin >> x >> y; v[x].push_back(y); } for (int i = 1; i <= n; ++i) { std::sort(v[i].begin(), v[i].end(), greater<>()); for (int j = 0; j < min(i, (int)v[i].size()); ++j) { res += v[i][j]; } } cout << res << endl; } signed main() { ios; int T = 1; cin >> T; while (T--) { solve(); } }

C. Insert Zero and Invert Prefix

题目大意

给定一个01数列 a,同时初始化一个空01数列 b,现在需要进行 n 次操作,每次操作可以选择 i[0,b.length - 1],将 b[0,i] 的元素取反,并在第i 位插入 0,后面的元素不动。问能否操作构造出 a 数列。

解题思路

从零构造不好做的话我们可以考虑正难则反,考虑逆向情况。

题目转化为删去 a 中的某个 0,然后将它前面的元素取反。

问能否通过恰好 n 次操作把 a 删干净。

我们可以双指针模拟这个过程,因为我们要取得最优情况一定是删去最靠前的 0,这样才能保证每次操作更改的数最少。

需要注意的是我们操作后,数列元素个数有变化,所以他们的编号也有变化,需要使用位置变量来存一下。

AC Code

#include <iostream> #include <algorithm> #include <cstring> #define endl '\n' #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr) using namespace std; typedef long long LL; const int N = 1e5 + 10; const int MOD = 1e9 + 7; int a[N], res[N]; void solve() { int n; cin >> n; for (int i = 1; i <= n; ++i) { cin >> a[i]; } int cnt = 0, pos = 1; for (int i = 1; i <= n; ++i) { if (!a[i]) { res[++cnt] = i - pos; for (int j = 1; j <= i - pos; ++j) { res[++cnt] = 0; } pos = i + 1; } } if (cnt != n) { cout << "NO" << endl; return; } cout << "YES" << endl; for (int i = n; i >= 1; --i) { cout << res[i] << ' '; } cout << endl; } signed main() { ios; int T = 1; cin >> T; while (T--) { solve(); } }

D. Ball Sorting

题目大意

n 个彩色球排成一列。这些球被涂成了 n 种不同的颜色,用数字从 1n 表示。从左边数第 i 个球涂成颜色 ci。现在需要重新排列这些球,使得从左边数第 i 个球的颜色为 i 。此外,你有 k1 个颜色为 0 的球,可以在重新排列过程中使用。

现在允许如下操作:

  1. 在序列的任意位置放置一个颜色为 0 的球,同时保持其他球的相对顺序。最多可以执行这个操作 k 次。
  2. 选择任意一个非零颜色的球同时至少有一个与它相邻的球颜色为 0,将该非零颜色的球移到序列的任意位置,同时保持其他球的相对顺序不变。你可以无限次执行这个操作,但是每次操作你需要支付 1 个硬币。

操作结束之后颜色为零的球会消失,问排序完成的最小代价是多少。

解题思路

首先看本题的数据范围,最大只到 500,那么 O(n3) 的dp可解。

本题实际上是全排列的排序问题,我们颜色为 0 的球可以让他相邻两边的球归位,而当这个球走了,0 就会与新的球相邻,那么每个 0 实际上可以控制一段连续的序列。那么我们可以dp一个LIS(最长上升子序列),同时计算不处于LIS的部分被分成了几段即可。

AC Code

#include <iostream> #include <algorithm> #include <cstring> #define endl '\n' #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr) using namespace std; typedef long long LL; const int N = 510; const int MOD = 1e9 + 7; int a[N]; int dp[N][N]; LL res[N]; void solve() { memset(dp, -0x3f, sizeof dp); int n; cin >> n; for (int i = 1; i <= n; ++i) { cin >> a[i]; } a[n + 1] = 0x3f3f3f3f; dp[1][0] = 1; for (int i = 2; i <= n; i++) { dp[i][1] = 1; } for (int i = 2; i <= n + 1; i++) { for (int k = 0; k <= i + 1; k++) { for (int j = 1; j < i; j++) { if (a[j] < a[i]) { if (j == i - 1) { dp[i][k] = max(dp[i][k], dp[j][k] + 1); } else if (k > 0) { dp[i][k] = max(dp[i][k], dp[j][k - 1] + 1); } } } } } for (int k = 1; k <= n; ++k) { dp[n + 1][k] = max(dp[n + 1][k], dp[n + 1][k - 1]); cout << n + 1 - dp[n + 1][k] << ' '; } cout << endl; } signed main() { ios; int T = 1; cin >> T; while (T--) { solve(); } }

__EOF__

本文作者叁纔
本文链接https://www.cnblogs.com/SanCai-Newbie/p/17464910.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   叁纔  阅读(38)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示