比赛链接

A

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
int n, m, k, H;
cin >> n >> m >> k >> H;
int cnt = 0;
for (int i = 1;i <= n;i++) {
int h;
cin >> h;
if (abs(h - H) % k) continue;
int d = abs(h - H) / k;
cnt += 1 <= d && d <= m - 1;
}
cout << cnt << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

B

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; int a[200007];
bool odd[200007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i], odd[i] = a[i] & 1;
sort(a + 1, a + n + 1);
for (int i = 1;i <= n;i++) if ((a[i] & 1) != odd[i]) return false;
cout << "YES" << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}

C

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; int c[200007];
bool solve() {
int n, k;
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> c[i];
int l = 1, cntl = 0;
while (cntl < k) {
if (l > n) return false;
cntl += c[1] == c[l];
l++;
}
l--;
int r = n, cntr = 0;
while (cntr < k) {
if (r < 1) return false;
cntr += c[n] == c[r];
r--;
}
r++;
if (l < r || c[1] == c[n]) cout << "YES" << '\n';
else return false;
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}

D

题意

给定长度为 \(n-1\) 的前缀和 \(a\) ,问原数组是否可能为一个长度为 \(n\) 的排列。

题解

知识点:枚举。

考虑还原各个元素,即 \(a_1,a_2-a_1,\cdots,a_{n-1}-a_{n-2}\) ,记为数组 \(b\) 。

我们记还原过程中重复的数字,或超出范围排列的数字为坏数。

我们发现,如果前缀和是由排列得到的,那么至多有一个坏数,我们分类讨论:

  1. 若没有坏数,那么一定可能。
  2. 若有一个坏数,则枚举排列中还未出现的数字,当且仅当未出现的数字的和等于坏数才可能。
  3. 若有多个坏数,则一定不可能。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; ll a[200007];
bool vis[200007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) vis[i] = 0;
for (int i = 1;i <= n - 1;i++) cin >> a[i];
ll bad = 0;
for (int i = 1;i <= n - 1;i++) {
ll d = a[i] - a[i - 1];
if (d > n || vis[d]) {
if (bad) return false;
bad = d;
}
else vis[d] = 1;
}
if (bad) {
int sum = 0;
for (int i = 1;i <= n;i++) {
if (!vis[i]) sum += i;
}
if (sum != bad) return false;
}
cout << "YES" << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}

E

题意

有 \(n\) 种药以及它们的价格 \(c_i\) ,现在其中 \(k\) 种免费供应,并给出每种药的合成配方(有些药只能买),每次合成需要的药会消耗掉之后要用就要再买,保证配方自己不能合成自己(直接或者间接都不能)。

问合成每种药的最少花费是多少。

题解

知识点:DAG上dp。

把关系建图,在dag上dp即可。

时间复杂度 \(O(n+k+n\sum m_i)\)

空间复杂度 \(O(n+k+n\sum m_i)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; vector<int> g[200007];
int c[200007];
int f[200007];
void dfs(int u) {
if (f[u] != -1) return;
f[u] = c[u];
ll sum = 0;
for (auto v : g[u]) {
dfs(v);
sum += f[v];
}
if (g[u].size()) f[u] = min(sum, (ll)f[u]);
} bool solve() {
int n, k;
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> c[i], f[i] = -1, g[i].clear();
for (int i = 1;i <= k;i++) {
int x;
cin >> x;
c[x] = 0;
}
for (int i = 1;i <= n;i++) {
int m;
cin >> m;
for (int j = 1;j <= m;j++) {
int v;
cin >> v;
g[i].push_back(v);
}
} for (int i = 1;i <= n;i++) if (f[i] == -1) dfs(i);
for (int i = 1;i <= n;i++) cout << f[i] << " \n"[i == n];
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

F

题意

给定 \(k\) 和 \(n\) 个数字的数组 \(a(a_i<2^k)\) 。

找到两个不同的位置 \(i,j\) 和数字 \(x < 2^k\) 使得 \((a_i \oplus x) \& (a_j \oplus x)\) 最大。

题解

方法一

知识点:位运算,贪心。

考虑 \(x\) 异或 \(a_i,a_j\) 对最后答案的影响。我们发现,对于某一位,只要 \(a_i,a_j\) 是同 \(1\) ,那么 \(x\) 只需要 \(0\) ;如果是同 \(0\) ,那么 \(x\) 只需要 \(1\) ,其他情况无论 \(x\) 这一位是什么最后结果都是 \(0\) 。

那么问题变为,找到同或 \(a_i \odot a_j\) 最大的即可(也可以是异或最小,两者是对称的)。

这里需要一个结论:一组数字同或最大(异或最小)的一对,一定出现在大小相邻的两个数字中。

感性的理解就是,大小相邻数字同 \(0,1\) 且出现在高位的情况比与其他数字匹配的情况多。

因此我们对数字从小到大排序,枚举每一对即可。

时间复杂度 \(O(n \log n)\)

空间复杂度 \(O(n)\)

方法二

知识点:位运算,Trie,贪心。

如果得不到上面的结论,我们可以考虑类似最大异或和问题一样用Trie解决。

显然,对于同或最大,从高位到低位贪心地保证数字相同即可,和异或最大刚好相反。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

方法一

#include <bits/stdc++.h>
using namespace std;
using ll = long long; pair<int, int> a[200007];
bool solve() {
int n, k;
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> a[i].first, a[i].second = i;
sort(a + 1, a + n + 1); int mx = -1;
array<int, 3> ans{};
for (int i = 2;i <= n;i++) {
int res = ~(a[i - 1].first ^ a[i].first) & ((1 << k) - 1);
if (res > mx) {
mx = res;
ans[0] = a[i - 1].second;
ans[1] = a[i].second;
ans[2] = (~a[i - 1].first & ~a[i].first) & ((1 << k) - 1);
}
}
cout << ans[0] << ' ' << ans[1] << ' ' << ans[2] << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

方法二

#include <bits/stdc++.h>
using namespace std;
using ll = long long; class Trie {
struct Node {
array<int, 2> nxt;
int val;
int id;
}; int bit;
vector<Node> node;
Node NIL; public:
Trie(int _bit = 0) { init(_bit); } void init(int _bit) {
bit = _bit;
NIL = { {0,0},0 };
node.assign(1, NIL);
} void insert(int s, int id) {
int p = 0;
for (int i = bit - 1;i >= 0;i--) {
int c = (s >> i) & 1;
if (!node[p].nxt[c]) {
node[p].nxt[c] = node.size();
node.push_back(NIL);
}
p = node[p].nxt[c];
}
node[p].val = s;
node[p].id = id;
} pair<int, int> find_max(int s) {
int p = 0;
for (int i = bit - 1;i >= 0;i--) {
int c = (s >> i) & 1;
if (node[p].nxt[c]) p = node[p].nxt[c];
else p = node[p].nxt[c ^ 1];
}
return { node[p].val,node[p].id };
}
}; bool solve() {
int n, k;
cin >> n >> k; Trie trie(k);
int mx = -1;
array<int, 3> ans{};
for (int i = 1, x;i <= n;i++) {
cin >> x;
if (i == 1) {
trie.insert(x, i);
continue;
}
auto [y, id] = trie.find_max(x);
int res = ~(x ^ y) & ((1 << k) - 1);
if (res > mx) {
mx = res;
ans[0] = i;
ans[1] = id;
ans[2] = (~x & ~y) & ((1 << k) - 1);
}
trie.insert(x, i);
}
cout << ans[0] << ' ' << ans[1] << ' ' << ans[2] << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

G

题意

有 \(n\) 个点,每个点的高度为 \(h_i\) ,有 \(m\) 条双向路径。

若 \(i,j\) 存在路径,则从 \(i\) 到 \(j\) 需要的体力是 \(h_i - h_j\) (负数则恢复体力),若没有足够的体力就不能走。

有 \(q\) 个询问,每个询问包含起点 \(a\) ,终点 \(b\) ,以及初始体力 \(e\) ,问能否从起点到终点。

题解

知识点:并查集,离线。

我们发现从 \(i\) 到 \(j\) 所需的体力一定为 \(h_i - h_j\) 。因此从 \(a\) 能不能走到 \(b\) ,取决于是否存在于一条路径使得,路径上的所有点的高度不超过 \(e + h_a\) 。

对于边 \((i,j)\) ,当且仅当能到达的高度大于等于两个端点时,这条边才有用,因此设边权为 \(\max(h_i,h_j)\) 。

此时,我们可以最小生成树+倍增在线求路径最大值(典中典),也可以离线+启发式合并+DSU处理询问,但这里采用离线+排序+DSU求,比较容易。

考虑对 \(e+h_a\) 从小到大排序,对边权从小到大排序,那么每次询问先将边权不超过 \(e+h_a\) 的边加入dsu再询问即可。

时间复杂度 \(O(n + m \log m + q(\log q + \log n))\)

空间复杂度 \(O(n + m + q)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; struct DSU {
vector<int> fa; DSU(int n = 0) { init(n); } void init(int n) {
fa.assign(n + 1, 0);
iota(fa.begin(), fa.end(), 0);
} int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } bool same(int x, int y) { return find(x) == find(y); } void merge(int x, int y) { fa[find(x)] = find(y); }
}; int h[200007];
tuple<int, int, int> e[200007];
tuple<int, int, int, int> Q[200007];
bool ans[200007]; bool solve() {
int n, m;
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> h[i];
for (int i = 1;i <= m;i++) {
int u, v;
cin >> u >> v;
e[i] = { u,v, max(h[u],h[v]) };
}
sort(e + 1, e + m + 1, [&](auto a, auto b) {return get<2>(a) < get<2>(b);}); int q;
cin >> q;
for (int i = 1;i <= q;i++) {
int u, v, w;
cin >> u >> v >> w;
Q[i] = { u,v,w + h[u], i };
}
sort(Q + 1, Q + q + 1, [&](auto a, auto b) {return get<2>(a) < get<2>(b);}); int pos = 1;
DSU dsu(n);
for (int i = 1;i <= q;i++) {
while (pos <= m && get<2>(e[pos]) <= get<2>(Q[i])) {
dsu.merge(get<0>(e[pos]), get<1>(e[pos]));
pos++;
}
ans[get<3>(Q[i])] = dsu.same(get<0>(Q[i]), get<1>(Q[i]));
}
for (int i = 1;i <= q;i++) cout << (ans[i] ? "YES" : "NO") << '\n';
cout << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

Codeforces Round #888 (Div. 3) A-G的更多相关文章

  1. Educational Codeforces Round 47 (Div 2) (A~G)

    目录 Codeforces 1009 A.Game Shopping B.Minimum Ternary String C.Annoying Present D.Relatively Prime Gr ...

  2. Educational Codeforces Round 46 (Div 2) (A~G)

    目录 Codeforces 1000 A.Codehorses T-shirts B.Light It Up C.Covered Points Count(差分) D.Yet Another Prob ...

  3. Educational Codeforces Round 45 (Div 2) (A~G)

    目录 Codeforces 990 A.Commentary Boxes B.Micro-World C.Bracket Sequences Concatenation Problem D.Graph ...

  4. Codeforces Round #582 (Div. 3)-G. Path Queries-并查集

    Codeforces Round #582 (Div. 3)-G. Path Queries-并查集 [Problem Description] 给你一棵树,求有多少条简单路径\((u,v)\),满足 ...

  5. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  6. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

  7. 贪心+模拟 Codeforces Round #288 (Div. 2) C. Anya and Ghosts

    题目传送门 /* 贪心 + 模拟:首先,如果蜡烛的燃烧时间小于最少需要点燃的蜡烛数一定是-1(蜡烛是1秒点一支), num[g[i]]记录每个鬼访问时已点燃的蜡烛数,若不够,tmp为还需要的蜡烛数, ...

  8. Codeforces Round #383 (Div. 2) 题解【ABCDE】

    Codeforces Round #383 (Div. 2) A. Arpa's hard exam and Mehrdad's naive cheat 题意 求1378^n mod 10 题解 直接 ...

  9. 模拟 Codeforces Round #249 (Div. 2) C. Cardiogram

    题目地址:http://codeforces.com/contest/435/problem/C /* 题意:给一组公式,一组数据,计算得到一系列的坐标点,画出折线图:) 模拟题:蛮恶心的,不过也简单 ...

  10. Codeforces Round #368 (Div. 2) B. Bakery (模拟)

    Bakery 题目链接: http://codeforces.com/contest/707/problem/B Description Masha wants to open her own bak ...

随机推荐

  1. 笔记:C++学习之旅---面向对象程序设计2

    笔记:C++学习之旅---面向对象程序设计2 面向对象程序设计基于三个基本概念:数据抽象.继承和动态绑定. 继承和动态绑定对程序的编写有两方面的影响:一是我们可以更容易的定义与其他类相似但不完全相同的 ...

  2. Solon 统一的返回结果调整

    使用 "统一的渲染控制" 可以对输出做统一的控制外...还可以借助路由拦截器 RouterInterceptor ,对 mvc 返回结果做提交确认机制(即可修改)进行控制(相对来讲 ...

  3. 2023-02-15:商场中有一展柜A,其大小固定,现已被不同的商品摆满, 商家提供了一些新商品B,需要对A中的部分商品进行更新替换, B中的商品可以自由使用,也就是可以用B中的任何商品替换A中的任何

    2023-02-15:商场中有一展柜A,其大小固定,现已被不同的商品摆满, 商家提供了一些新商品B,需要对A中的部分商品进行更新替换, B中的商品可以自由使用,也就是可以用B中的任何商品替换A中的任何 ...

  4. 2022-09-14:以下go语言代码输出什么?A:0 0;B:0 1;C:1 1;D:1 0。 package main func main() { println(f(1)) } func

    2022-09-14:以下go语言代码输出什么?A:0 0:B:0 1:C:1 1:D:1 0. package main func main() { println(f(1)) } func f(x ...

  5. 2021-10-03:合并两个有序数组。非递减数组nums1和nums2。合并这两个数组并放在nums1中。力扣88。

    2021-10-03:合并两个有序数组.非递减数组nums1和nums2.合并这两个数组并放在nums1中.力扣88. 福大大 答案2021-10-03: 从右往左遍历nums1和nums2,谁大拷贝 ...

  6. Jenkins - Windows环境修改主目录路径

    Jenkins - Windows环境修改主目录路径 前言 如果Jenkins部署在Windows环境中,Jenkins主目录默认在 C:\Users\用户名\.jenkins下: 所有Jenkins ...

  7. .NET 通过源码深究依赖注入原理

    依赖注入 (DI) 是.NET中一个非常重要的软件设计模式,它可以帮助我们更好地管理和组织组件,提高代码的可读性,扩展性和可测试性.在日常工作中,我们一定遇见过这些问题或者疑惑. Singleton服 ...

  8. 深入 Hyperf:HTTP 服务启动时发生了什么?

    当我们创建 Hyperf 项目之后,只需要在终端执行 php bin/hyperf.php start 启动命令,等上几秒钟,就可以看到终端输出的 Worker 进程已启动,HTTP 服务监听在 95 ...

  9. 如何在前端应用中合并多个 Excel 工作簿

    本文由葡萄城技术团队于博客园原创并首发.葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言|问题背景 SpreadJS是纯前端的电子表格控件,可以轻松加载 Excel 工作簿中的数据 ...

  10. Anaconda入门使用指南(二)

    Anaconda 安装完成,在 bin 子目录下( $PREFIX/bin )可以看到该发行版本预装好的 conda.python.pip.jupyter,以及一些常用的工具. Python环境管理 ...