Codeforces Round #847 (Div. 3) A-G
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\) 表示数字的个数:
- 如果 \(x > pre + 1\) ,我们就必须开新的 \(cnt_x\) 个分组,答案加 \(cnt_x\) 。
- 如果 \(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\) :
首先满足 \(a \oplus b = x\) ,显然 \(a_i,b_i\) 必须是一个 \(1\) 和一个 \(0\) ,我们不妨设 \(a_i = 1,b_i = 0\) 。
其次要满足 \(\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一遍附近找到最近的距离,主要在两个优化上:
- 用 \(f_u\) 记录距离 \(u\) 最近的黑点的距离,每次只更新 \(f_v > f_u+1\) 的情况,能有效减小bfs的范围。
- 用 \(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 在图点上,可以按照以下步骤移动:
- 开局可以随意移动一个。
- 若某次
token移动到了bonus点,那么可以有一次移动其他token机会。 token可以重叠。- 某次移动使得
token到编号为 \(1\) 的点,则游戏立刻胜利。
问游戏是否会胜利。
题解
知识点:模拟,贪心,枚举。
我们从两方面考虑:
- 能使
token到达 \(1\) 的路径。 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的更多相关文章
- Educational Codeforces Round 47 (Div 2) (A~G)
目录 Codeforces 1009 A.Game Shopping B.Minimum Ternary String C.Annoying Present D.Relatively Prime Gr ...
- 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 ...
- Educational Codeforces Round 45 (Div 2) (A~G)
目录 Codeforces 990 A.Commentary Boxes B.Micro-World C.Bracket Sequences Concatenation Problem D.Graph ...
- Codeforces Round #582 (Div. 3)-G. Path Queries-并查集
Codeforces Round #582 (Div. 3)-G. Path Queries-并查集 [Problem Description] 给你一棵树,求有多少条简单路径\((u,v)\),满足 ...
- Codeforces Round #368 (Div. 2)
直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...
- Codeforces Round #279 (Div. 2) ABCDE
Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name A Team Olympiad standard input/outpu ...
- 贪心+模拟 Codeforces Round #288 (Div. 2) C. Anya and Ghosts
题目传送门 /* 贪心 + 模拟:首先,如果蜡烛的燃烧时间小于最少需要点燃的蜡烛数一定是-1(蜡烛是1秒点一支), num[g[i]]记录每个鬼访问时已点燃的蜡烛数,若不够,tmp为还需要的蜡烛数, ...
- 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 题解 直接 ...
- 模拟 Codeforces Round #249 (Div. 2) C. Cardiogram
题目地址:http://codeforces.com/contest/435/problem/C /* 题意:给一组公式,一组数据,计算得到一系列的坐标点,画出折线图:) 模拟题:蛮恶心的,不过也简单 ...
- Codeforces Round #368 (Div. 2) B. Bakery (模拟)
Bakery 题目链接: http://codeforces.com/contest/707/problem/B Description Masha wants to open her own bak ...
随机推荐
- 深入理解Kafka核心设计及原理(一):初识Kafka
转载请注明出处: 1.1 kafka简介 Kafka 起初是由 Linkedin 公司采用 Scala 语言开发的一个多分区.多副本且基于 ZooKeeper协调的分布式消息系统,现己被捐献给 Apa ...
- Icoding 链表 删除范围内结点
1.题目: 已知线性表中的元素(整数)以值递增有序排列,并以单链表作存储结构.试写一高效算法,删除表中所有大于mink且小于maxk的元素(若表中存在这样的元素),分析你的算法的时间复杂度. 链表结点 ...
- Go-竞态条件-锁
1. 产生环境 多个进程(process).线程(threading)或协程(routine)存在对同一个资源访问顺序敏感(时间上的错误) 2. 概念 临界区 -- 时间上对同一资源的读写产生的数据不 ...
- [转帖]故障分析 | 让top命令直接显示Java线程名?-- 解析OpenJDK的一个bug修复
https://zhuanlan.zhihu.com/p/413136873 作者:阎虎青DBLE 开源项目负责人,负责分布式数据库中间件研发工作:持续专注于数据库方面的技术,始终在一线从事开发:对数 ...
- [转帖]mysql 数据库视图迁移
https://www.cnblogs.com/phpyangbo/p/6132821.html 最近做一个项目,为了方便查询,建了好多的视图表,正式上线的时候需要把本地数据库迁移到服务器上. 按照常 ...
- [转帖]UseG1GC垃圾回收技术解析
https://www.cnblogs.com/yuanzipeng/p/13374690.html 介绍 G1 GC,全称Garbage-First Garbage Collector,通过-XX: ...
- pytest-xdist分布式
使用pytest框架运行每条case的时候,都是上一条运行结束才会运行下一条,要是有成千上百条case 且每条运行2s那就是2*总条数,会浪费大量的时间和人力.为了节约时间和人力成本,pytest提供 ...
- 【JS 逆向百例】37网游登录接口参数逆向
声明 本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 逆向目标 目标:37网游登录 主页:https://www.37.co ...
- 微信小程序网页嵌入开发
无脑开发 下载微信开发者工具 新建一个项目找到index开头的进去全选删除粘贴下面代码 <!-- html --> <!-- 指向嵌入外部链接的地址 --> <web-v ...
- net8来了
11 月 15 日开始的为期三天的 .NET Conf 在线活动的开幕日上,.NET 8作为微软的开源跨平台开发平台正式发布..NET 团队着重强调云.性能.全栈 Blazor.AI 和 .NET M ...