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 ...
随机推荐
- 【FreeRTOS】任务调度
启动调度器接口,主要是创建空闲任务和定时器任务以及执行特定架构的启动调度器接口 // FreeRTOS\Source\tasks.c void vTaskStartScheduler( void ) ...
- Java - 获取个十百千位数
int n= 1234: System.out.println(n%10 ); //获取个位 System.out.println((n/10)%10 ); //获取十位 System.out.pri ...
- [转帖]tgz 安装clickhouse
一.什么是clickhouse ClickHouse是开源的列式存储数据库(DBMS),主要用于在线处理查询(OLAP),能够使用SQL查询实时生成数据分析报告. 下面介绍下安装clickhouse. ...
- goofys 鲲鹏上面编译挂载与性能测试
goofys 鲲鹏上面编译挂载与性能测试 介质 使用go进行编译. 官网上面有 amd64的介质,但是没有aarch64的介质 需要自行编译 前几天一直编译失败. 周天在家自己测试了一把,根据gith ...
- [转帖]dd 自动压测与结果解析脚本
测试串行.并发.读.写 4类操作,每类操作又可以指定各种bs及count值,循环压测.每种场景一般执行3次,取平均值. 一. 串行写 #!/bin/sh bs_list=(256k 1024k 10M ...
- [转帖]一文浅析Nginx线程池!
https://zhuanlan.zhihu.com/p/616500765 Nginx通过使用多路复用IO(如Linux的epoll.FreeBSD的kqueue等)技术很好的解决了c10k ...
- CentOS7上面一键部署rabbitmq的简单方法
1. rabbitmq的安装部署比redis之类的要麻烦一些. 主要是他是基于erlang写的 而不是基于c或者是c++写的 2. 很多时候编译需要添加很多组件, 但是一些机器可能不会让添加这么多的组 ...
- rabbitmq rpm包安装以及简单设置用户的方法
公司有一台性能比较好的power机器. 同事要求安装rabbitmq 今天尝试进行了一下处理 公司里面有网络有相应的源 性能还不错 第一步安装一下依赖的erlang yum install erlan ...
- 京音平台-一起玩转SCRM之电销系统
作者:京东科技 李良文 一.前言 电销是什么?就是坐席拿着电话给客户打电话吗?no no no,让我们一起走进京音平台之电销系统. 京音平台2020年初开始建设,过去的两年多的时间里,经历了跌宕起伏, ...
- linux时间和当前时间相关8小时问题
依次执行如下的代码: 1.更改时区 cp /usr/share/zoneinfo/GMT /etc/localtime ln -sf /usr/share/zoneinfo/Asia/Shanghai ...