Codeforces Round 858 (Div. 2)
A CF1086A Walking Master
解一个二元一次方程组就行,注意特殊判断无解的情况。
B CF1086B Mex Master
Description
给定一个含 个非负整数的序列 ,求对 重新排序后序列的最小分数。
一个序列 的分数为:不包含在序列 中的最小非负整数。
Solution
当序列 中 的个数不大于 时,可以将序列排成 的样子,不在该序列中,答案为 ;
否则,若序列全为 ,则答案为 ;
否则,或序列中的最大值比 大时,设它为 ,可以将序列排成 ,由于,故答案为 ;
否则,即序列中仅有 和 ,且 的个数比 多,可以将序列排成 ,则答案为。
Code
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 5;
int n, a[N], ans = -1;
int main() {
int T;
cin >> T;
while (T--) {
cin >> n;
int ind = 0, x, cnt_0 = 0, maxa = 0;
for (int i = 1;i <= n;++i) {
cin >> x;
if (x == 0) {
++cnt_0;
continue;
}
a[++ind] = x;
maxa = max(maxa, x);
}
if (cnt_0 <= (n + 1) / 2) {
cout << "0" << endl;
continue;
}
if (maxa > 1 || maxa == 0) {
cout << "1" << endl;
continue;
}
cout << "2" << endl;
}
return 0;
}
CF1086C Sequence Master
Description
对于正整数 ,构造有 个元素的序列,满足:从中任意取出 个元素,它们的乘积与剩下 个元素的和相等。
给定长度为 的序列 ,构造满足上述条件的序列 ,使得 最小。
只需输出最小的 ,无需输出构造的序列 。
Solution
首先考虑如何构造序列 。
注意到,满足条件的 是很少数的。
① 容易发现, 是一个解,则答案为
② 时,只需满足 即可,易得答案为
③ 若所有元素相等且不为 ,即,
即需解出 ,仅有一个解:
④ 若有不等的元素,假设 ,有:
(1)
(2)
(3)
(1)-(2)得:
因为 ,所以
需要满足任从中取 个数,它们得乘积都为
故
注意到只有 为偶数时,这种情况才有解 (4)
将(4)代入(1)得: (5)
将(4)代入(3)得: (6)
联合(5)和(6)解得: 或
综上所述,当$n%2=0 {a}$有解
那么接下来只需要确定把 放在序列中的哪个位置即可:放在 最大的位置。
Conclusion
写下容易得到的特殊解;
对 从小到大进行讨论;
分元素都相等和有不等两种情况讨论:
相等的情况直接解方程,
不等的情况,假设出两个不等的元素,写下等式并进行运算(如相减),解出答案。
注意特殊情况和前提条件。
Code
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
const int N = 4e5 + 5;
int n, p[N];
ll ans;
ll min(ll x, ll y) {
return x < y ? x : y;
}
int main() {
int T;
cin >> T;
while (T--) {
ans = 0;
cin >> n;
for (int i = 1;i <= n * 2;++i) {
cin >> p[i];
ans += abs(p[i]);
}
if (n == 1) //特殊情况勿漏
ans = min(ans, abs(p[1] - p[2]));
if (n == 2) {
ll tmp_ans = 0;
for (int i = 1;i <= n * 2;++i)
tmp_ans += abs(p[i] - 2);
ans = min(ans, tmp_ans);
}
if (n % 2 == 0) { //清楚前提条件
int pos = 1, val = abs(p[1] + 1) - abs(p[1] - n);
for (int i = 1;i <= n * 2;++i)
if (val < abs(p[i] + 1) - abs(p[i] - n))
pos = i, val = abs(p[i] + 1) - abs(p[i] - n);
ll tmp_ans = 0;
for (int i = 1;i <= n * 2;++i)
if (i == pos) tmp_ans += abs(p[i] - n);
else tmp_ans += abs(p[i] + 1);
ans = min(ans, tmp_ans);
}
cout << ans << endl;
}
return 0;
}
CF1086 D DSU Master
CF1086E Tree Master
Description
给定一棵有 个结点的树,结点标号从 到 ,每个结点 有一个权值 。记结点 的父结点为 ,树根 的父结点记为 。
对于结点 和 ,定义 为:
初始
和 都不为
·
· ,
给出 个询问,对于第 个询问给出的 ,求出 。
Solution
记忆化搜索。
注意用 来记忆化会TLE,需要记录在数组中,使得用的时间可以完成一次查询。具体来说,记录 为第 个结点与同层编号(注意这个编号不是结点标号,而是对树的某一层从开始的编号)为 的结点的答案。由于空间的限制,我们只能记录某一层的总结点数小于某个值(我设的是)时的答案。
可以证明记搜的时间和空间复杂度都是:【没看懂这个证明,还在研究】
Code
#include<iostream>
#include<cmath>
#include<map>
#include<vector>
#include<cstring>
#define ll long long
using namespace std;
const int N = 1e5 + 5, M = 1000;
int n, q, a[N], p[N], cnt[N], dep[N], num[N];
ll rem[N][M];
vector<int>to[N];
ll calc(int x, int y) {
if (x == 0)
return 0;
int d = dep[x];
if (cnt[d] < M && rem[x][num[y]] != -1)
return rem[x][num[y]];
ll ret = 1ll * a[x] * a[y] + calc(p[x], p[y]); //注意这里的1ll
if (cnt[d] < M)
rem[x][num[y]] = ret;
return ret;
}
void dfs(int u, int depth) {
dep[u] = depth;
num[u] = ++cnt[dep[u]];
for (int v : to[u])
dfs(v, depth + 1);
}
int main() {
cin >> n >> q;
for (int i = 1;i <= n;++i) cin >> a[i];
for (int i = 2;i <= n;++i) {
cin >> p[i];
to[p[i]].push_back(i);
}
dfs(1, 0);
memset(rem, -1, sizeof(rem));
while (q--) {
int x, y;
cin >> x >> y;
cout << calc(x, y) << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现