Loading

「解题报告」Codeforces Round #884 (Div. 1 + Div. 2) Editorial

比赛地址:Dashboard - Codeforces Round 884 (Div. 1 + Div. 2) - Codeforces

个人评价:这场是构造专场!

A. Subtraction Game

Problem - A - Codeforces

有一堆石子(应该是石子),每次只能拿走 \(a\) 块或者 \(b\) 块,最先不能移动的人输,构造一个数 \(n\),使得先手必输。

两种构造方法:

  1. 构造一个数 \(n\) 小于 \(\min\{a, b\}\)

  2. 构造一个数 \(n\)\((a + b) \le n \ < (a + b + \min\{a, b\})\)

其实就是变相的 a + b

/*
  The code was written by yifan, and yifan is neutral!!!
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

int T;

void solve() {
	ll a = read<ll>(), b = read<ll>();
	cout << a + b << '\n';
}

int main() {
	T = read<int>();
	while (T --) {
		solve();
	}
	return 0;
}

B. Permutations & Primes

Problem - B - Codeforces

给定一个整数 \(n\),要求构造一个 \(1 \sim n\) 的排列,使得这个排列的素数值最大

素数值定义:若一个子区间的 \(\operatorname{mex}\) 是一个质数,那么素数值加一。

\(\operatorname{mex}\):一个区间中最小的没有出现的非负整数,但在本题中不讨论 \(0\),因此在本题中的含义是最小的没有出现的正整数。

构造方法:

  1. \(1\) 放在中间。如果一个区间不包括 \(1\),那么这个区间对素数值的贡献为 \(0\),想让贡献最大,\(1\) 放在中间。

  2. 第一个位置放 \(2\),最后一个位置放 \(3\)。只要包括 \(1, 2\),但不包括 \(3\),则 \(\operatorname{mex} = 3\),是质数;包括 \(1, 3\),但不包括 \(2\),则 \(\operatorname{mex} = 2\),也是质数;当同时包括 \(1, 2, 3\) 时,区间长度为 \(n\),即 \(\operatorname{mex} = n + 1\),对于所有的排列,都会有这个最大的区间,因此就可以不考虑它,即可以不考虑同时包括 \(1, 2, 3\) 的情况。

  3. 剩下的空位随便排

/*
  The code was written by yifan, and yifan is neutral!!!
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 2e5 + 5;

int T;
int ans[N];

void work() {
	int n = read<int>();
	for (int i = 1; i <= n; ++ i) {
		ans[i] = 0;
	}
	ans[1] = 2, ans[n] = 3, ans[n / 2 + 1] = 1;
    // 这里这样写就不用特判 1 的情况了
	for (int i = 2, k = 4; i < n; ++ i) {
		if (!ans[i]) {
			ans[i] = k;
			++ k;
		}
	}
	for (int i = 1; i <= n; ++ i) {
		cout << ans[i] << " ";
	}
	putchar('\n');
}

int main() {
	T = read<int>();
	while (T --) {
		work();
	}
	return 0;
}

C. Particles

Problem - C - Codeforces

给定一个 \(n\) 个整数(可以为负)的序列,可以从中删掉某个位置的数,然后把这个位置的左右两边的数加在一起,合成一个新的元素(两个元素合为一个,数量也减一),如果左右元素为空,就不合并。按此操作直到最后只剩一个数,求最大可能的数。

将奇数位置的数和偶数位置的数各自提取出来,可以发现,只有奇数位置的数能与奇数位置的数合并,同理,也只有偶数位置的数可以和偶数位置的数合并(后面简称奇数集和偶数集),即最后的答案一定为奇数集的和或偶数集的和。

对于负数的情况,我们总可以将负数都删去,如果存在一个负数删掉后左右两边出现了一个正数或一个负数,那么一定会使奇数集或偶数集的答案减小,至于让哪个集的和减小,哪个集的和成为答案的可能性小,就让哪个集的和减小。

对于全是负数的极端情况,输出序列的最大值即可。

/*
  The code was written by yifan, and yifan is neutral!!!
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 2e5 + 5;

int n;
int a[N];

void solve() {
	n = read<int>();
	bool fg = 1;
	ll ans1 = 0, ans2 = 0;
	for (int i = 1; i <= n; ++ i) {
		a[i] = read<int>();
		fg &= (a[i] < 0);
	}
	if (fg) {
		cout << *max_element(a + 1, a + n + 1) << '\n';
		return ;
	}
	for (int i = 1; i <= n; ++ i) {
		if (i & 1) {
			ans1 += max(a[i], 0);
		}
		else {
			ans2 += max(a[i], 0);
		}
	}
	cout << max(ans1, ans2) << '\n';
	return ;
}

int main() {
	int T = read<int>();
	while (T --) {
		solve();
	}
	return 0;
}

D. Row Major

Problem - D - Codeforces

非正解 暴力跑过去了?

构造一个字符串,长度为 \(n\),该字符串可以一次转化成一个 \(r \times c\) 的矩阵(即 \(r \times c = n\)),是的矩阵中相邻元素相等的情况最少。

首先,在序列中相邻的元素不能相同,之后枚举 \(n\) 的因数,判断矩阵中上下相邻的元素是否相同即可。

/*
  The code was written by yifan, and yifan is neutral!!!
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 1e6 + 5;

vector<int> y;
char s[N];
bool vis[127];

void solve() {
	y.clear();
	memset(s, '\0', sizeof s);
	int n = read<int>();
	int lim = sqrt(n);
	for (int i = 2; i <= lim; ++ i) {
		if (n % i == 0) {
			y.emplace_back(i);
			y.emplace_back(n / i);
		}
	}
	s[1] = 'a';
	for (int i = 2; i <= n; ++ i) {
		for (int j = 'a'; j <= 'z'; ++ j) {
			vis[j] = 0;
		}
		int tmp = 'a';
		vis[(int)s[i - 1]] = 1;
		while (vis[tmp])	++ tmp;
		for (int j : y) {
			if (i - j <= 0)	continue ;
			vis[(int)s[i - j]] = 1;
			while (vis[tmp]) {
				++ tmp;
			}
			if (tmp > 'z')	tmp = 'z';
		}
		s[i] = tmp;
	}
	for (int i = 1; i <= n; ++ i) {
		putchar(s[i]);
	}
	putchar('\n');
}

int main() {
	int T = read<int>();
	while (T --) {
		solve();
	}
	return 0;
}

E 往后,题解就看不懂了,就不再补了。

posted @ 2023-07-12 11:26  yi_fan0305  阅读(254)  评论(0编辑  收藏  举报