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

Codeforces Round 1051 (Div. 2) A~D2

A. All Lengths Subtraction

思维。

每次选择长度为 \(k(k \in [1,n])\) 的区间减 \(1\),那么第一个首选的就是 \(a_i = n\) 的 位置,然后维护 \(n\) 所在的区间,检查 \(n-k+1\) 是否在其两边,有的话就扩大区间,否则就肯定不能实现。

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

B. Discounts

贪心。

由于价值 \(x\) 的劵需要购买 \(x-1\) 个最贵的,那么为了付出的钱更少白嫖的物品价值更高,那我们肯定得选择 \(x\) 小的劵去购买从大到小排序后前 \(x\) 个物品,按此方法模拟即可。

点击查看代码
#include <bits/stdc++.h>using namespace std;using i64 = long long;void solve() {int n, k;cin >> n >> k;vector<int> a(n + 1), b(k + 1);for (int i = 1; i <= n; i += 1) {cin >> a[i];}for (int i = 1; i <= k; i += 1) {cin >> b[i];}sort(a.begin() + 1, a.end());sort(b.begin() + 1, b.end());i64 ans = 0;int idx = 1;for (int i = n; i >= 1; i -= 1) {if (idx <= k && i - b[idx] + 1 >= 1) {for (int j = i; j > i - b[idx] + 1; j -= 1) {ans += a[j];}i = i - b[idx] + 1;idx += 1;}else {ans += a[i];}}cout << ans << "\n";}
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}

C. Max Tree

拓扑。

首先贪心的想,要想最大化贡献,那对于每一条边来说,其实就已经有了个评判标准,按照评判标准确定谁连向谁,父亲的值要大于儿子,所以只要对进入队列的点依次赋值 \(n,n-1,n-2...\) 即可。

我这里是按照贡献贪心的去判定边的连向,不过貌似多此一举了,因为只有 \(n-1\) 条边,所以只要对每条边判一下谁的贡献更大就可以确定朝向了。

点击查看代码
#include <bits/stdc++.h>using namespace std;using i64 = long long;void solve() {int n;cin >> n;vector<array<int,3>> Q;for (int i = 1; i < n; i += 1) {int u, v, x, y;cin >> u >> v >> x >> y;Q.push_back({x, u, v});Q.push_back({y, v, u});}vector<int> in(n + 1);vector e(n + 1, vector<int>());set<array<int,2>> has;sort(Q.begin(), Q.end(), greater<>());for (auto &[_, u, v] : Q) {if (has.count({u, v}) || has.count({v, u})) {continue;}has.insert({u, v});in[v] += 1;e[u].push_back(v);}int now = n;vector<int> ans(n + 1);queue<int> pq;for (int i = 1; i <= n; i += 1) {if (in[i] == 0) {pq.push(i);}}while (pq.size()) {auto u = pq.front();pq.pop();ans[u] = now --;for (auto &v : e[u]) {if (!--in[v]) {pq.push(v);}}}for (int i = 1; i <= n; i += 1) {cout << ans[i] << " \n"[i == n];}}
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}

D1. Inversion Graph Coloring (Easy Version)

dp。

手推或者打表能发现一条规律,那就是对于 \(i<j< k\) 来说,存在 \(a_i > a_j > a_k\) 这样的序列是不合法的,因为这会导致三个点两两不同颜色,但我们最多只能涂两个颜色,即严格最长下降子序列的长度小于等于 \(2\),否则无法实现。

\(dp_{i,j,k}\) 表示前 \(i\) 个数中最长下降子序列的第一个数为 \(j\),第二个数为 \(k\) 的方案数。
那么当我们不选第 \(i\) 个数时,有转移:

\[dp_{i,j,k}=dp_{i-1,j,k} \]

选择第 \(i\) 个数时,有转移:

\[\begin{aligned} dp_{i,a_i,k} = dp_{i,a_i,k} + dp_{i-1,j,k} & & a_i \ge j \\ dp_{i,j,a_i} = dp_{i,j,a_i} + dp_{i-1,j,k} & & j > a_i \ge k \end{aligned} \]

\(a_i < k\) 时,会形成长度为 \(3\) 的下降子序列,所以是不合法的转移。

代码中 Z 类型为取模类。

点击查看代码
using Z = ModInt<MOD[0]>;void solve() {int n;cin >> n;vector<int> a(n + 1);for (int i = 1; i <= n; i += 1) {cin >> a[i];}Z ans = 0;vector dp(n + 1, vector<Z>(n + 1));dp[0][0] = 1;for (int i = 1; i <= n; i += 1) {vector ndp(n + 1, vector<Z>(n + 1));for (int j = 0; j <= n; j += 1) {for (int k = 0; k <= j; k += 1) {ndp[j][k] += dp[j][k];if (a[i] >= j) {ndp[a[i]][k] += dp[j][k];}else if (a[i] >= k) {ndp[j][a[i]] += dp[j][k];}}}dp = move(ndp);}for (int i = 0; i <= n; i += 1) {for (int j = 0; j <= n; j += 1) {ans += dp[i][j];}}cout << ans << "\n";}
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}

D2. Inversion Graph Coloring (Hard Version)

数据结构优化 dp。

观察以上转移,可以发现,其实有 \(dp_{i,a_i,k} = \sum_{j=0}^{a_i}dp_{i-1,j,k},\ dp_{i,j,a_i}=\sum_{k=0}^{a_i}dp_{i-1,j,k}\)

这两个前缀和部分可以用树状数组维护,把 \(j、k\) 展平到二维上,就是一个维护第 \(k\) 列前 \(j\) 行的和,一个维护第 \(j\) 行前 \(k\) 列的和。

由于 \(n\le 2000\), 所以一定是要滚动的,一个方法是先把要转移的状态和值存下来放到最后转移。

如果你的树状数组不是从 \(1\) 开始的,记得偏移 \(1\) 位。

代码中 Z 是取模类。

点击查看代码
using Z = ModInt<MOD[0]>;template<typename T>
struct BIT {int n;vector<T> w;BIT() {}BIT(int n) {this->n = n;w.resize(n + 1);}void update(int x, T k) {for (; x <= n; x += x & -x) {w[x] += k;}}T ask(int x) {T ans = 0;for (; x; x -= x & -x) {ans += w[x];}return ans;}T ask(int x, int y) {return ask(y) - ask(x - 1);}
};void solve() {int n;cin >> n;vector<int> a(n + 1);for (int i = 1; i <= n; i += 1) {cin >> a[i];}Z ans = 0;vector f(2, vector(n + 1, BIT<Z>(n + 2)));f[0][0].update(1, 1);f[1][0].update(1, 1);for (int i = 1; i <= n; i += 1) {vector<tuple<int,int,Z>> st;for (int j = 0; j <= a[i]; j += 1) {Z res = f[0][j].ask(a[i] + 1);st.emplace_back(a[i], j, res);}for (int j = a[i] + 1; j <= n; j += 1) {Z res = f[1][j].ask(a[i] + 1);st.emplace_back(j, a[i], res);}for(auto &[u, v, res] : st){f[0][v].update(u + 1, res);f[1][u].update(v + 1, res);}}for (int i = 0; i <= n; i += 1) {ans += f[1][i].ask(n + 1);}cout << ans << "\n";}
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}
http://www.hskmm.com/?act=detail&tid=9982

相关文章:

  • 【F#学习】数组:Array
  • CTFWEB姿势总结
  • 规模化加速AI:从用户、开发者到企业的深度策略解析
  • ctfshow 菜狗杯
  • 国际服务器(VPS):泰国、印尼、菲律宾、马来西亚、香港、台湾、新加坡、日本、美国、英国等。
  • 缓存常见问题
  • ctfshow 电子取证
  • Hello,World!
  • 最新IDEA 2025 专业版破解永久破解教程(附资源)intellij IDEA
  • AtCoder ABC423F - Loud Cicada 题解 容斥原理
  • 1756:八皇后
  • 矩阵置零-leetcode
  • 嘉立创常用快捷键
  • 02020402 EF Core基础02-EF Core数据的增删改查
  • conda 无法安装依赖 CondaHTTPError: HTTP 000 CONNECTION FAILED for url: tsinghua tencentaliyun
  • 牛客刷题-Day2
  • 图解支付系统账务系统核心设计 - 智慧园区
  • vulnhub(持续更新)
  • 小爱同学连接电脑进行交互 教程
  • 网络流初步浅谈:EK与Dinic
  • 解码C语言结构体
  • 已完成今日求所有满足长为 $a$ 的和为 $b$ 的按位或为 $c$ 的非负整数序列的异或和的异或和大学习
  • Hello Yqc!
  • 2025.9.19——卷9-10选择
  • 软件工程学习日志2025.9.19
  • ECT-OS-JiuHuaShan 框架元推理,是人类良医与福音
  • upload-labs全通关
  • SAPO去中心化训练:多节点协作让LLM训练效率提升94%
  • mybatis-plus学习笔记
  • 区间问题