Codeforces Round 858 (Div. 2)

A CF1086A Walking Master

解一个二元一次方程组就行,注意特殊判断无解的情况。

B CF1086B Mex Master

Description

给定一个含 n 个非负整数的序列 a,求对 a 重新排序后序列的最小分数。

一个序列 b 的分数为:不包含在序列 [b1+b2,b2+b3,...,bn1+bn] 中的最小非负整数。

Solution

当序列 a0 的个数不大于 n/2 时,可以将序列排成 [0,x,0,x,...](x0) 的样子,0不在该序列中,答案为0

否则,若序列全为 0 ,则答案为 1

否则,或序列中的最大值比 1 大时,设它为 x,可以将序列排成 [0,...,0,x,ai,...,ak],由于x>1ai0,故答案为 1

否则,即序列中仅有 10,且 0 的个数比 1 多,可以将序列排成 [0,...,0,1,0,1,0,1],则答案为2

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

对于正整数 n ,构造有 2n 个元素的序列,满足:从中任意取出 n 个元素,它们的乘积与剩下 n 个元素的相等。

给定长度为 2n 的序列 p,构造满足上述条件的序列 a,使得 i=12n|aipi| 最小。

只需输出最小的 i=12n|aipi|,无需输出构造的序列 a

Solution

首先考虑如何构造序列 a

注意到,满足条件的 a 是很少数的。

① 容易发现,a1=a2=...=an=0 是一个解,则答案为 |pi|

n=1时,只需满足 a1=a2即可,易得答案为 |p1p2|

③ 若所有元素相等且不为 0,即a1=a2=...=an0

​ 即需解出 na1=a1nn=a1n1 ,仅有一个解:n=2a1=a2=a3=a4=2

④ 若有不等的元素,假设 a1a2 ,有:

a1a3...anan+1=a2+an+2+...+a2n (1)

a2a3...anan+1=a1+an+2+...+a2n (2)

a1a2...an1an=an+1+an+2+...+a2n (3)

(1)-(2)得:(a1a2)a3...an+2=a2a1

因为 a1a2,所以 a3a4....an+2=1

需要满足任从{a3,a4,...,a2n}中取 n1 个数,它们得乘积都为 1

a3=a4=...=a2n

注意到只有 n 为偶数时,这种情况才有解 a3=a4=...=a2n=1 (4)

将(4)代入(1)得:a1+a2=n1 (5)

将(4)代入(3)得:a1a2=n (6)

联合(5)和(6)解得:a1=n,a2=1a1=1,a2=n

综上所述,当$n%2=0 {a}$有解 {n,1,1,...,1}

那么接下来只需要确定把 n 放在序列中的哪个位置即可:放在 |pi+1||pin|最大的位置。

Conclusion

写下容易得到的特殊解

n 从小到大进行讨论;

元素都相等和有不等两种情况讨论:

相等的情况直接解方程,

不等的情况,假设出两个不等的元素,写下等式并进行运算(如相减),解出答案。

注意特殊情况前提条件

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

给定一棵有 n 个结点的树,结点标号从 1n,每个结点 i 有一个权值 i 。记结点 i 的父结点为 pi ,树根 1 的父结点记为 0

对于结点 xy,定义 f(x,y) 为:

​ 初始 ans=0

while(xy 都不为 0 )

​ · ansans+axay

​ · xpxypy

f(x,y)=ans

给出 q 个询问,对于第 i 个询问给出的 xi,yi,求出 f(xi,yi)

Solution

记忆化搜索。

注意map 来记忆化会TLE,需要记录在数组中,使得用O(1)的时间可以完成一次查询。具体来说,记录 rem[x][i] 为第 x 个结点与同层编号(注意这个编号不是结点标号,而是对树的某一层从1开始的编号)为 i 的结点的答案。由于空间的限制,我们只能记录某一层的总结点数小于某个值(我设的是1000)时的答案。

可以证明记搜的时间和空间复杂度都是O(nn):【没看懂这个证明,还在研究】

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;
}
posted @   DTTTTTTT-  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示