Codeforces Round 996 (Div. 2)

https://codeforces.com/contest/2055

A. Two Frogs

题意:有一排莲叶,1~n,两个青蛙 A 和 B ,起初分别位于 a 和 b,每一个回合可以向左向右跳一格,前提是这个莲叶上没有青蛙。当一个青蛙不能跳了,它就输了。A 先跳,A 能赢吗?

题解:A 和 B 分别跳一个回合,他们之间的距离的奇偶性不会改变。最后 A 和 B 之间的距离为 0,并且轮到 A 的回合了,那么 A 就输了。反之 B 输。递推到距离为 2,还是 A 输。所以当距离为偶数就是 A 输。

void slove() {
	int n, a, b; cin >> n >> a >> b;
	int c = abs(a - b) - 1;
	if (c & 1) {
		cout << "YES" << endl;
	} else {
		cout << "NO" << endl;
	}
} 

B. Crafting

题意:给定两个数组 a, b,长度都为 n。在数组 a 可以选择一个元素 i,使得 \(a_i:=a_i + 1\) ,其它所有元素,\(j \in [1, n] \and j \neq i\ \and a_j \geq 1,\ a_j := a_j - 1\) 。可以操作任意次,最后能否使得 a 的每一个都至少为 b。

题解:对于一个位置 \(a_i < b_i\) ,那么这个位置就需要操作,累加 1 的话,a 的总和要减小 n - 1。如果有两个位置 \(a_i < b_i, a_j < b_j\) ,那么无论如果都不能使得 a 变成 b,因为一个位置增加多少,另外一个位置就需要减少多少。所以最多只能有一个位置比 b 小。并且其它位置增量都必须大于等于这个差值。

void slove() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++) {
		cin >> b[i];
	}
	int cnt = 0;
	int c = 0, minv = 1e9;
	for (int i = 1; i <= n; i++) {
		if (a[i] < b[i]) {
			cnt++;
			c = b[i] - a[i];
		} else {
			minv = min(minv, a[i] - b[i]);
		}
		if (cnt >= 2) {
			cout << "NO" << endl;
			return;
		}
	}
	if (minv >= c) {
		cout << "YES" << endl;
	} else {
		cout << "NO" << endl; 
	}
} 

C. The Trail

题意:给定一个 \(n\times m\) 的矩阵,给定一条路径,只有 D 和 R 字符组成,D 表示向下一格,R 表示向右一格。起点为 \((1, 1)\) 终点为 \((n, m)\) 。那么路径的长度为 \(n+m-2\)。路径对应矩阵上值为 0,要求填充路径对应的格点,使得每一行和每一列都相等。

题解:设一行或一列的和为 sum,那么整个矩阵的和可以表示为:\(n\times sum\) 或者 \(m\times sum\), 那么存在关系:\(n\times sum=m\times sum\)\(n\neq m \Rightarrow sum=0, \ n=m\Rightarrow sum \in R\) .
如果依次填充的,每一步都可以找到一行或一列只差一个空位没有填充。不妨直接使得这一行或这一列为 0。

void slove() {
	cin >> n >> m;
	string s; cin >> s;
	for (int i  = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
		}
	}
	int x = 1, y = 1;
	for (char c : s) {
		if (c == 'D') {
			LL sum = 0;
			for (int i = 1; i <= m; i++) {
				sum += a[x][i];
			}
			a[x][y] = -sum;
			x++;
		} else {
			LL sum = 0;
			for (int i = 1; i <= n; i++) {
				sum += a[i][y];
			}
			a[x][y] = -sum;
			y++;
		}
	}
	LL sum = 0;
	for (int i = 1; i <= m; i++) {
		sum += a[x][i];
	}
	a[x][y] = -sum;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
} 

D. Scarecrow

题意:给定一个数组表示稻草人的初始位置,有一只乌鸦起初位于 0,稻草人可以以每秒一个单位的速度向左右移动。每当存在稻草人位于乌鸦的位置或者乌鸦的左边,使得二者距离小于 k,乌鸦就会瞬间移动到稻草人的右边距离 k。比如:存在一个稻草人位于 y 处,一个乌鸦位于 x 处。\(y\leq x\), 如果 \(x-y < k\) ,那么乌鸦就会从 x 移动到 \(y+k\) 。最后使得乌鸦的位置大于等于 L,至少需要多少时间,输出时间的2倍。

题解:输出时间的2倍,是考虑精度,1 秒移动 1 格,可以 0.5 秒移动半格。全局乘 2 即可。
起初肯定需要第一个稻草人移动到 0 的位置,使得乌鸦处于 k 处。记录全局需要的时间,以及乌鸦当前的位置。

从第二个稻草人开始,依次处理每一个稻草人。稻草人的位置 \(a_i\), 乌鸦当前的位置 \(pos\)

  1. \(pos \geq a_i\) ,乌鸦位于这个稻草人的右边,那么现在 i 的左边的稻草人都无用了。只需要考虑 i 这个稻草人即可。首先可以移动到 \(min(a_i+time, pos)\) ,乌鸦可以移动到哪里呢?\(min(a_i+time, pos) + k\) 。当前位于 pos 位置是被 i-1 位置的稻草人赶过来的,\(pos-a_{i-1} \geq k\)\(pos \geq a_i \geq a_{i-1}\)\(a_i+time\) 是目前第 i 个稻草人最远可以移动的位置,必然不小于第 i-1 个稻草人最远可以移动的位置。那么第 i 个稻草人最多可以使得乌鸦移动到 \(min(a_i+time, pos) + k\) 肯定比前面的稻草人更远。
  2. \(pos<a_i\)。这种情况下,乌鸦位于第 i 个稻草人和第 i - 1 个稻草人之间。且 \(pos-a_{i-1} \geq k\) 。那么最优的决策是,两个稻草人往中间移动,第 i-1 个稻草人每向右移动一格,就会使得乌鸦往右移动一格。同时第 i 个稻草人往左移动一格,会使得乌鸦和第 i 个稻草人之间的距离缩减 2 格。0.5 秒的话,就缩减 1 格,这也是为什么会出现移动 0.5 秒的原因。此时消耗的时间就是 \(\frac{(a_i-pos)}{2}\) 。乌鸦移动 \(\frac{a_i-pos}{2}+k\)
void slove() {
	cin >> n >> k >> l;
	k *= 2, l *= 2;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i] *= 2;
	}
	int res = a[1], pos = k;
	for (int i = 2; i <= n; i++) {
		if (pos >= a[i]) {
			a[i] = min(a[i] + res, pos);
			pos = a[i] + k;
		} else {
			a[i] = max(a[i] - res, pos);
			int t = (a[i] - pos) / 2;
			pos += t + k;
			res += t;
		}
	}
	if (pos < l) {
		res += l - pos;
	}
	cout << res << endl;
} 
posted @ 2025-10-06 18:41  yairr  阅读(10)  评论(0)    收藏  举报