当前位置: 首页 > news >正文

Educational Codeforces Round 182 (Rated for Div. 2)


A. Cut the Array

题意:把数组分成三段,使得每段和模\(3\)后的值都相同或者都不相同。

\(n\)很小,暴力枚举分段就行了。

点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::vector<int> sum(n + 1);for (int i = 0; i < n; ++ i) {sum[i + 1] = sum[i] + a[i];}for (int l = 1; l <= n; ++ l) {for (int r = l + 1; r < n; ++ r) {std::set<int> s;s.insert(sum[l] % 3);s.insert(((sum[r] - sum[l]) % 3 + 3) % 3);s.insert(((sum[n] - sum[r]) % 3 + 3) % 3);if (s.size() == 1 || s.size() == 3) {std::cout << l << " " << r << "\n";return;}}}std::cout << 0 << " " << 0 << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}

B. Maximum Cost Permutation

题意:一个排列,有些地方给出了,有些地方是\(0\)代表没给出。一个排列的价值为一个长度最小的子区间,使得排序这个子区间后使得数组升序。求所有合法的排列中价值最大的。

一个完全给出的排列,就是从前往后找第一个\(p_i\ne i\)的位置和最后一个这样的位置。答案就是这两个位置的区间长度。
那么现在有些地方没填,如果\(p_i\)等于\(0\)且这个地方不是必须填\(i\),则这个地方可以使得\(p_i \ne i\),发现必须填\(i\)的情况为只有一个\(0\)的时候才有可能出现,否则一定可以使得\(p_i \ne i\)。分类讨论一下。

点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::vector<int> a(n);std::vector<int> st(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];-- a[i];if (a[i] >= 0) {st[a[i]] = 1;}}int cnt = std::ranges::count(a, -1);int l = 0;while (l < n) {if (a[l] != -1 && a[l] == l) {++ l;} else {break;}}int r = n - 1;while (r >= 0) {if (a[r] != -1 && a[r] == r) {-- r;} else {break;}}if (cnt == 0) {l = n;for (int j = 0; j < n; ++ j) {if (a[j] != j) {l = j;break;}}r = 0;for (int j = n - 1; j >= 0; -- j) {if (a[j] != j) {r = j;break;}}std::cout << std::max(0, r - l + 1) << "\n";return;}if (cnt == 1) {for (int i = 0; i < n; ++ i) {if (a[i] == -1 && !st[i]) {l = n;for (int j = 0; j < n; ++ j) {if (i != j && a[j] != j) {l = j;break;}}r = 0;for (int j = n - 1; j >= 0; -- j) {if (i != j && a[j] != j) {r = j;break;}}std::cout << std::max(0, r - l + 1) << "\n";return;}} }std::cout << std::max(0, r - l + 1) << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}

C. Non-Descending Arrays

题意:两个数组\(a, b\)。你可以选择一些下标,使得这些下标对应的位置交换\(a_i, b_i\)。最后要使得两个数组都是升序。求方案数。

显然\(i\)只有交换和不交换两个状态。那么记\(f[i][0/1]\)表示第\(i\)个位置交换/不交换使得前缀升序的方案数,那么考虑\(i-1\)交不交换,看两个位置是否合法。

代码省略取模类。

点击查看代码
constexpr int P = 998244353;
using Z = MInt<P>;void solve() {int n;std::cin >> n;std::vector<int> a(n), b(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}for (int i = 0; i < n; ++ i) {std::cin >> b[i];}std::vector f(n, std::array<Z, 2>{});f[0][0] = f[0][1] = 1;for (int i = 1; i < n; ++ i) {if (a[i] >= a[i - 1] && b[i] >= b[i - 1]) {f[i][0] += f[i - 1][0];}if (a[i] >= b[i - 1] && b[i] >= a[i - 1]) {f[i][0] += f[i - 1][1];}if (b[i] >= a[i - 1] && a[i] >= b[i - 1]) {f[i][1] += f[i - 1][0];}if (b[i] >= b[i - 1] && a[i] >= a[i - 1]) {f[i][1] += f[i - 1][1];}}std::cout << f[n - 1][0] + f[n - 1][1] << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}

D. Price Tags

题意:两个数组的差异为对于每个数\(x\),两个数组的\(x\)的数量的个数差之和。给你\(n\)个数,你要选择一个大于\(1\)的正整数\(x\),使得每个\(a_i = \lceil \frac{a_i}{x} \rceil\)。然后价值为操作后的数组的和加上操作前数组和操作后数组的差异乘\(y\)。求最大价值。

\(max\)\(a\)中最大值,那么对于一个\(x\),所有数操作后的值域都在\([1, \lceil \frac{max}{x} \rceil]\)之间,那么考虑枚举\(x\),对于一个值\(i\),除\(x\)向上取整后会变成\(i\)的数的范围为\([(i - 1) \times x + 1, i\times x]\),用前缀和记录这个范围原本有多少数,就可以得到和原本\(i\)的个数的差异。

点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;i64 y;std::cin >> n >> y;const int N = 2e5;std::vector<int> sum(N + 1), c(N + 1);int max = 0;for (int i = 0; i < n; ++ i) {int x;std::cin >> x;++ c[x];max = std::max(max, x);}for (int i = 1; i <= N; ++ i) {sum[i] = c[i] + sum[i - 1];}if (max == 1) {std::cout << n << "\n";return;}i64 ans = -1e18;for (int x = 2; x <= max; ++ x) {int up = std::ceil(1.0 * max / x);i64 v = 0;for (int i = 1; i <= up; ++ i) {int l = (i - 1) * x + 1, r = std::min(max, i * x);if (l > max) {break;}int cnt = sum[r] - sum[l - 1];v += (i64)cnt * i;v -= std::max(0, cnt - c[i]) * y;}ans = std::max(ans, v);}std::cout << ans << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}

E1. Looking at Towers (easy version)

题意:对于一个数组\(a\),定义\(L(a)\)为所有\(i\)满足\(a_i > pre_{i-1}\)\(a_i\)构造的序列,其中\(pre_i\)表示前\(i\)个数的最大值,同理\(R(a)\)表示满足\(a_i> suf_{i+1}\)\(a_i\)构成的序列,其中\(suf_i\)表示后缀最大值。求\(a\)有多少个子序列\(a'\)满足\(L(a') = L(a), R(a') = R(a)\)

求出\(L(a)\)。记\(fl[i][j]\)为前\(i\)个数已经填了\(L(a)\)的前\(j\)个数的方案数,\(gl[i][j]\)表示前\(i\)个数\(a_i\)必须选填了\(L(a)\)\(j\)个数的方案数。则讨论\(a_i\)是否加入到子序列里来转移。同理记\(fr[i][j], gr[i][j]\)\(i\)\(n\)的方案数。
\(L(a)\)长度为\(ml\)\(R(a)\)长度为\(mr\),那么考虑第一个\(a_i = max\)\(i\),如果\(L(a')\)选择了这个位置,那么如果\(R(a')\)也选择了,则有\(gl[i][ml] \times fr[i + 1][mr]\)贡献,如果\(R(a')\)不选,则枚举\(R(a')\)最后一个选择的地方,即\(\sum_{j=i+1}^{n} gl[i][ml] \times gr[j][mr]\)。如果不选两个都不包含\(a_i\),则枚举后面的\(max\),让\(L(a')\)不包含这个位置,\(R(a')\)包含这个位置,也就是\(\sum_{j=i+1}^{n} [a_j == max](fl[j][ml - 1] \times gr[j][mr])\)

代码省略取模类。

点击查看代码
constexpr int P = 998244353;
using Z = MInt<P>;void solve() {int n;std::cin >> n;std::vector<int> a(n + 1);for (int i = 1; i <= n; ++ i) {std::cin >> a[i];}int max = std::ranges::max(a);std::vector<int> L, R;for (int i = 1; i <= n; ++ i) {if (L.empty() || a[i] > L.back()) {L.push_back(a[i]);}}for (int i = n; i >= 1; -- i) {if (R.empty() || a[i] > R.back()) {R.push_back(a[i]);}}int ml = L.size();std::vector fl(n + 1, std::vector<Z>(ml + 1));std::vector gl(n + 1, std::vector<Z>(ml + 1));fl[0][0] = 1;for (int i = 1; i <= n; ++ i) {for (int j = 0; j <= ml; ++ j) {fl[i][j] += fl[i - 1][j];if (j && a[i] <= L[j - 1]) {fl[i][j] += fl[i - 1][j];gl[i][j] += fl[i - 1][j];}if (j && a[i] == L[j - 1]) {fl[i][j] += fl[i - 1][j - 1];gl[i][j] += fl[i - 1][j - 1];}}}	int mr = R.size();std::vector fr(n + 2, std::vector<Z>(mr + 1));std::vector gr(n + 2, std::vector<Z>(mr + 1));fr[n + 1][0] = 1;for (int i = n; i >= 1; -- i) {for (int j = 0; j <= mr; ++ j) {fr[i][j] += fr[i + 1][j];if (j && a[i] <= R[j - 1]) {fr[i][j] += fr[i + 1][j];gr[i][j] += fr[i + 1][j];}if (j && a[i] == R[j - 1]) {fr[i][j] += fr[i + 1][j - 1];gr[i][j] += fr[i + 1][j - 1];}}}Z ans = 0;for (int i = 1; i <= n; ++ i) {if (a[i] == max) {ans += gl[i][ml] * (fr[i + 1][mr] + fr[i + 1][mr - 1]);for (int j = i + 1; j <= n; ++ j) {if (a[j] == max) {ans += fl[j][ml - 1] * gr[j][mr];}}break;}}std::cout << ans << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
http://www.wxhsa.cn/company.asp?id=5170

相关文章:

  • java第二周课前提问
  • java GC
  • Redis最佳实践——性能优化技巧之监控与告警详解
  • week1
  • EF Core 与 MySQL:迁移和关系配置详解
  • 《原子习惯》-读书笔记2
  • CF1626D 题解
  • Python 集合运算:并集、交集、差集全解析
  • 第一周数据可视化作业
  • 用 C++ + OpenCV + Tesseract 实现英文数字验证码识别
  • java 第一节课课前提问
  • 二进制解码器、选通器和分配器
  • 2025最新版 Photoshop软件免费下载安装完整教程(PS2025)超详细安装教程
  • nac一键卸载软件脚本
  • 交叉编译openharmony版本的openssh
  • 为什么不建议在 Docker 中跑 MySQL
  • CFD
  • [MCP][05]Elicitation示例
  • Warsaw主题关闭导航条
  • Python Socket网络编程(2)
  • PS2025安装包下载及PS2025安装包安装教程详细步骤(包含安装包下载链接)
  • Nature Genetics | 本周最新文献速递
  • 关于go里切片作为函数参数时是引用传递还是值传递
  • DRAN读写循环
  • 数据结构操作相关
  • Neisbitt 不等式的证法
  • 端口转发神器Rinetd:轻量级安装与配置指南
  • C语言中递归思想的应用
  • WITH RECURSIVE 递归公用表表达式(CTE)
  • leetcode 3541. 找到频率最高的元音和辅音 便捷