比赛链接

A

题意

判断输入字符串与 \(\pi\) 的最长前缀匹配,不超过 \(30\) 位。

题解

知识点:模拟。

抄样例最后一个 \(30\) 都正确的,直接匹配。

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

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

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
string s;
cin >> s;
string pi = "314159265358979323846264338327";
int cnt = 0;
for (int i = 0;i < s.size();i++) {
if (s[i] != pi[i]) break;
cnt++;
}
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

题意

有 \(n\) 个骰子,数字 \(a_i \in [1,6]\) 的面朝上,现在给你骰子面朝上数字的总和 \(s\) ,以及去掉一个最大值的数字总和 \(r\) ,要求还原一个合法的 \(a_i\) 。

题解

知识点:枚举。

方法有很多,这里提供一种写起来很方便的。

先存一个最大值 \(mx = s - r\) ,依次给每个骰子分配点数 \(\min(mx,r)\) ,超过最大值直接给最大值。

但是为了保证不出现数字为 \(0\) 的情况,一开始先给所有骰子分配 \(1\) 点。

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

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

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
int n, s, r;
cin >> n >> s >> r;
s -= n;
r -= n - 1;
int mx = s - r;
cout << mx + 1 << ' ';
for (int i = 2;i <= n;i++) {
cout << min(r, mx) + 1 << ' ';
r -= min(r, mx);
}
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;
}

C

题意

对一个排列 \(p\) ,生成 \(n\) 个长为 \(n-1\) 新序列,第 \(i\) 个序列由 \(p\) 除了 \(p_i\) 的元素构成。

现在给你 \(p\) 生成的 \(n\) 个序列,但顺序是打乱的,要求还原一个合法的 \(p\) 。

题解

知识点:构造。

注意到 \(p_1\) 在 \(n\) 个序列的第一位会出现 \(n-1>1\) 次,而 \(p_2\) 只会出现 \(1\) 次 ,我们可以直接确定 \(p_1\) 。确定了 \(p_1\) ,我们找到没有 \(p_1\) 的一个序列,里面包含了 \(p_2,\cdots,p_n\) 直接输出即可。

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

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

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; int a[107][107];
int cnt[107];
bool solve() {
int n;
cin >> n;
int fst = 0;
vector<int> cnt(n + 1);
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n - 1;j++) {
cin >> a[i][j];
}
cnt[a[i][1]]++;
if (cnt[a[i][1]] > 1) fst = a[i][1];
}
cout << fst << ' ';
for (int i = 1;i <= n;i++) {
if (a[i][1] != fst) {
for (int j = 1;j <= n - 1;j++) cout << a[i][j] << " \n"[j == n - 1];
break;
}
}
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;
}

D

题意

给定一组数 \(a_i\) ,要求分出最少的分组,每组要求由连续上升的正整数构成。

对于连续上升,如 \(3,4,5,6\) 是连续上升的,而 \(1,3,4,5\) 不是,因为 \(1,3\) 中间跳过了 \(2\) 。

题解

知识点:贪心,枚举。

map 记录每个数的个数,从小到大遍历,设当前数字为 \(x\) ,上一次的数字为 \(pre\) , \(cnt\) 表示数字的个数:

  1. 如果 \(x > pre + 1\) ,我们就必须开新的 \(cnt_x\) 个分组,答案加 \(cnt_x\) 。
  2. 如果 \(x = pre + 1\) ,则可以与上一次共用分组 \(cnt_x\) 个分组,但如果 \(cnt_x>cnt_{pre}\) ,那么多出来的部分要开新的分组,答案加 \(cnt_x-cnt_{pre}\) 。

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

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

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
int n;
cin >> n;
map<int, int> mp;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
mp[x]++;
}
int ans = 0, pre = -1;
for (auto [x, y] : mp) {
if (x > pre + 1) ans += y;
else ans += max(0, y - mp[pre]);
pre = x;
}
cout << ans << '\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;
}

E

题意

给定一个正整数 \(x \leq 2^{29}\) ,找到两个正整数 \(a,b \leq 2^{32}\) ,满足 \(\dfrac{a+b}{2} = a \oplus b = x\) 。

题解

知识点:位运算,构造。

我们分析 \(x\) 的第 \(i\) 位 \(x_i = 1\) ,则 \(a,b\) 相关位置的情况,假设 \(a,b\) 一开始都为 \(0\) :

  1. 首先满足 \(a \oplus b = x\) ,显然 \(a_i,b_i\) 必须是一个 \(1\) 和一个 \(0\) ,我们不妨设 \(a_i = 1,b_i = 0\) 。

  2. 其次要满足 \(\dfrac{a+b}{2} = x\) ,根据1得到的 \(a_i+b_i = 1\) 不能满足除以 \(2\) 使得 \(x_i = 1\) ,考虑对附近其他位做调整。

    考虑调整 \(i+1\) 位,那么 \(a_{i+1},b_{i+1}\) 必须是一个 \(1\) 和一个 \(0\) ,我们不妨设 \(a_{i+1} = 1,b_{i+1} = 0\) 。但是,这样 \(x_{i+1}\) 必须等于 \(1\) ,假设 \(x_{i+1}=1\),那么对于 \(i+1\) 位的第二步因为第 \(i\) 位锁定了,只能再往 \(i+2\) 位考虑,这是没有尽头的,所以这条路走不通。

    考虑调整 \(i-1\) 位,那么就必须 \(a_{i-1} = b_{i-1} = 1\) 才能产生一个进位使得 \(x_i = 1\) 。此时, \(x_{i-1}\) 必须等于 \(0\) ,假设 \(x_{i-1} = 0\) 就恰好满足所有需求。

综上,对于任何一个 \(x_i = 1\) 要满足 \(x_{i-1} = 0\) 时才有解(特别地, \(x_1 = 1\) 时无解)。满足有解条件后,我们考虑令 \(a_i = 1,b_i = 0\) , \(a_{i-1} = b_{i-1} = 1\) ,即 \(a = 3 \cdot \dfrac{x}{2},b = \dfrac{x}{2}\) 。

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

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

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
int x;
cin >> x;
int y = x >> 1;
if ((x & 1) || (x & y)) return false;
else cout << (x | y) << ' ' << y << '\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

题意

题解

方法一

知识点:根号分治,bfs,贪心。

做法很简单,每加入一个黑点就bfs一遍附近找到最近的距离,主要在两个优化上:

  1. 用 \(f_u\) 记录距离 \(u\) 最近的黑点的距离,每次只更新 \(f_v > f_u+1\) 的情况,能有效减小bfs的范围。
  2. 用 \(ans\) 答案来限制搜索深度,因为距离大于 \(ans\) 的点没必要更新了,下一次更新 \(ans\) 一定在 \(f_u \leq ans-1\) 的情况。

证明:

在前 \(\sqrt n\) 次,一定能使得 \(ans\) 小于等于 \(2\sqrt n\) ,期间最多遍历 \(n\sqrt n\) 次。

在这之后,优化1能保证每个点只会在 \(f\) 变小时被遍历,优化2保证更新的距离不超过 \(ans \leq 2\sqrt n\) 。综上,每个点的 \(f\) 最多只会被更新 \(2\sqrt n\) 次,即每个点遍历不会超过 \(2 \sqrt n\) 次。

综上复杂度是 \(O(n\sqrt n)\)

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

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

方法二

知识点:根号分治,dfs,贪心。

不同于方法一的bfs遍历,这种方法设 \(f_u\) 为以 \(u\) 为根的子树中到 \(u\) 最近的黑点的距离,这样每次只需要更新 \(u\) 到根节点 \(1\) 路径上的点即可,并且保证更新层数不超过当前的 \(ans\) ,就可以做到和方法一一样的复杂度,但实际上跑的更快。

证明同方法一类似,前 \(\sqrt n\) 次能让 \(ans \leq 2\sqrt n\) ,后续每次遍历不超过 \(ans \leq 2\sqrt n\) 个点。

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

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

代码

方法一

#include <bits/stdc++.h>
using namespace std;
using ll = long long; struct Graph {
struct edge {
int v, nxt;
};
int idx;
vector<int> h;
vector<edge> e; Graph(int n, int m):idx(0), h(n + 1), e(m + 1) {}
void init(int n) {
idx = 0;
h.assign(n + 1, 0);
} void add(int u, int v) {
e[++idx] = { v,h[u] };
h[u] = idx;
}
};
const int N = 200007, M = N << 1;
int c[N];
Graph g(N, M);
int f[N]; bool solve() {
int n;
cin >> n >> c[1];
for (int i = 2;i <= n;i++) cin >> c[i];
g.init(n);
for (int i = 1;i < n;i++) {
int u, v;
cin >> u >> v;
g.add(u, v);
g.add(v, u);
} for (int i = 1;i <= n;i++) f[i] = n + 1;
int ans = n + 1;
for (int i = 1;i <= n;i++) {
ans = min(ans, f[c[i]]);
f[c[i]] = 0;
queue<int> q;
q.push(c[i]);
while (!q.empty()) {
int u = q.front();
q.pop();
if (f[u] >= ans - 1) continue;
for (int j = g.h[u];j;j = g.e[j].nxt) {
int v = g.e[j].v;
if (f[v] > f[u] + 1) {
f[v] = f[u] + 1;
q.push(v);
}
}
}
if (i > 1) cout << ans << " \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;
}

方法二

#include <bits/stdc++.h>
using namespace std;
using ll = long long; struct Graph {
struct edge {
int v, nxt;
};
int idx;
vector<int> h;
vector<edge> e; Graph(int n, int m):idx(0), h(n + 1), e(m + 1) {}
void init(int n) {
idx = 0;
h.assign(n + 1, 0);
} void add(int u, int v) {
e[++idx] = { v,h[u] };
h[u] = idx;
}
};
const int N = 200007, M = N << 1;
int c[N];
Graph g(N, M);
int fa[N];
int f[N]; void dfs(int u, int fa) {
::fa[u] = fa;
for (int i = g.h[u];i;i = g.e[i].nxt) {
int v = g.e[i].v;
if (v == fa) continue;
dfs(v, u);
}
} bool solve() {
int n;
cin >> n >> c[1];
for (int i = 2;i <= n;i++) cin >> c[i];
g.init(n);
for (int i = 1;i < n;i++) {
int u, v;
cin >> u >> v;
g.add(u, v);
g.add(v, u);
}
dfs(1, 0); for (int i = 1;i <= n;i++) f[i] = n + 1;
int ans = n + 1;
for (int i = 1;i <= n;i++) {
int u = c[i], dis = 0;
while (u && dis < ans) {
ans = min(ans, dis + f[u]);
f[u] = min(f[u], dis);
dis++;
u = fa[u];
}
if (i > 1)cout << ans << " \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;
}

G

题意

给一张 \(n\) 个点 \(m\) 条边的连通无向图,在图上的 \(b\) 个点会存在 bonus 标记(不可移动)。游戏开始前,会存在 \(p\) 个 token 在图点上,可以按照以下步骤移动:

  1. 开局可以随意移动一个。
  2. 若某次 token 移动到了 bonus 点,那么可以有一次移动其他 token 机会。
  3. token 可以重叠。
  4. 某次移动使得 token 到编号为 \(1\) 的点,则游戏立刻胜利。

问游戏是否会胜利。

题解

知识点:模拟,贪心,枚举。

我们从两方面考虑:

  1. 能使 token 到达 \(1\) 的路径。
  2. token 能提供多少次移动机会。

先考虑何种路径才能到达 \(1\) 。为了保证每次移动都有下次机会,那么到 \(1\) 的路径除了起点和终点 \(1\) 都必须是 bonus 点。同时,我们还需要知道移动几次才能到达 \(1\) ,方便后面比较其他点的贡献。因此,我们从 \(1\) bfs,遇到不是 bonus 的点只更新距离,不放队列扩展。

再考虑 token 能提供多少机会。在此之前,我们对 bonus 点的性质进行讨论,发现如果 bonus 点相邻另一个 bonus 点,那么进入这个 bonus 点就能提供无限次机会,而剩下一些孤儿 bonus 点,则进入这个点只会提供一次机会,因此我们先对 bonus 点记录是否无限的状态,这个可以在建图的时候就处理好。之后,我们遍历所有 token ,如果他们的邻居是无限 bonus 点则可以提供无限次机会,这里可以记为 \(n\) 次;如果他们的邻居是孤儿 bonus 点则只能提供一次,记为 \(1\) 次。

最后我们求出 token 贡献总和,枚举每个 token 点判断能否到达 \(1\) 。如果可达,则减去这个点的贡献求出其他点的总贡献,如果其他点的贡献大于等于距离减 \(1\) (开局第一次移动不需要任何 bonus )则一定可以到达。

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

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

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; const int N = 200007;
vector<int> g[N];
int st[N], dis[N], val[N]; bool solve() {
int n, m;
cin >> n >> m;
int p, b;
cin >> p >> b;
for (int u = 1;u <= n;u++) st[u] = 0, g[u].clear(), dis[u] = -1, val[u] = 0;
for (int i = 1, x;i <= p;i++) cin >> x, st[x] |= 1;
for (int i = 1, x;i <= b;i++) cin >> x, st[x] |= 2;
for (int i = 1;i <= m;i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
if ((st[u] & 2) && (st[v]) & 2) {
st[u] |= 4;
st[v] |= 4;
}
}
dis[1] = 0;
queue<int> q;
q.push(1);
while (!q.empty()) {
int u = q.front();
q.pop();
for (auto v : g[u]) {
if (~dis[v]) continue;
dis[v] = dis[u] + 1;
if (st[v] & 2) q.push(v);
}
}
for (int u = 1;u <= n;u++) if (st[u] & 1) for (auto v : g[u]) if (st[v] & 2) { val[u] = st[v] & 4 ? n : 1;if (st[v] & 4) break; }
ll sum = 0;
for (int u = 1;u <= n;u++) if (st[u] & 1) sum += val[u];
for (int u = 1;u <= n;u++) if (st[u] & 1) if (~dis[u] && sum - val[u] >= dis[u] - 1) { cout << "YES" << '\n'; return true; }
return false;
} 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;
}

Codeforces Round #847 (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. maven开源仓库

    在公司开发一般都用公司内部的maven仓库,但回家之后,就访问不了公司的网络,使用不了公司的maven仓库,只能使用开源的maven仓库. 在网上搜索和整理了几个比较好用的maven开源镜像仓库,记录 ...

  2. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.27)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  3. UofTCTF 2024 比赛记录

    这次的题目挺有意思,难度适中,*开头的代表未做出,简单记录一下解题笔记. Introduction General Information 题目 The flag format for all cha ...

  4. [转帖]查询 HTTPS 网站 TLS 版本

    参考 检查网站的TLS版本 – wentao's blog Linux curl 命令详解 - 腾讯云开发者社区-腾讯云 TLS 版本查询_天泽岁月的博客-CSDN博客_查看tls版本 使用 Open ...

  5. [转帖]awk的printf格式化输出

    https://www.cnblogs.com/chanix/p/12738097.html awk的printf格式化输出20121108 Chenxincat sort_result.txt223 ...

  6. [转帖]SMEMBERS:获取集合包含的所有元素

    https://www.bookstack.cn/read/redisguide/spilt.4.291fab46a3b4f05c.md SMEMBERS set 以下代码展示了如何使用 SMEMBE ...

  7. [转帖]k8s ipv4/ipv6双栈实践

    https://www.iceyao.com.cn/post/2020-11-28-k8s_dual_stack/ Posted by 爱折腾的工程师 on Saturday, November 28 ...

  8. [转帖]通过拓扑 label 进行副本调度

    https://docs.pingcap.com/zh/tidb/stable/schedule-replicas-by-topology-labels#%E5%9F%BA%E4%BA%8E%E6%8 ...

  9. [转帖]Nginx 使用与异常处理

    http://jartto.wang/2017/04/15/nginx-exception-handling/ 以前总是偷懒使用 Http-Server 来启动一个本地服务,后来花时间学习了一下 Ng ...

  10. [转帖]Day64_Kafka(二)

    第二讲 Kafka架构 课程大纲 课程内容 学习效果 掌握目标 Kafka架构 Kafka就 掌握 Kafka ack Exactly once Kafka log Kafka log 掌握 Kafk ...