Codeforces Round 859 (Div. 4)E~G

Codeforces Round 859 (Div. 4)E~G

E. Interview(二分,前缀和)

题意

给n堆石头,所有的石头里面只有一个重量为2,其他都是1,要找出重量为2的石头在哪一堆

思路

这类题目的关键点就是要找出正常和异常

假设我们现在讨论[l,r]这个区间(先认为这里面都是重量为1的石头,因为也不知道重量为2的石头在哪里),那么我肯定认为这个区间的所有石头重量和,就是它的前缀和sum[r] - sum[l-1]

但是如果我们询问之后

告诉我们的重量和多了1,那么就不正常,那就说明我们要找的那个石头就在这个区间里面,这是异常

如果重量和我们想的一样,那重量为2的石头肯定不在这个区间,而在别的区间,这是正常

所以我们就可以逮着整个区间的一半区间去提问,如果回答是正常,那么答案肯定在另一半区间。把另一半区间当成新的区间,抛弃掉提问的正常的区间。如果回答是异常,那就保留异常的那个区间,去提问就好了

代码

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

int ask(int l, int r) {
	cout << "? " << r - l + 1 << " ";
	for (int i = l; i <= r; i++) {
		if (i != l)cout << " ";
		cout << i;
	}
	cout << endl;
	int x; cin >> x;
	return x;
}

void solve() {
	int n; cin >> n;
	vector<int>a(n + 1), sum(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		sum[i] = sum[i - 1] + a[i];
	}
	int l = 1, r = n;
	int res = 1, mid;
	while (l <= r) {
		mid = (l + r) >> 1;
		int total = ask(l, mid);
		if (total != sum[mid] - sum[l - 1]) {
			res = mid;
			r = mid - 1;
		}
		else {
			l = mid + 1;
		}
	}
	cout << "! " << res << endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	return 0;
}

F. Bouncy Ball(模拟)

题意

给小球的起点、终点、起始方向,遇到了墙就会反弹,问反弹多少次可以到终点

思路

这个反弹,就有一个结论就是

我们当前这个网格是n * m的,每格都可以有四种状态(四个方向),所以整个网格最多有4 * n * m种状态,我们最多走4 * n * m步,就可以走完所有可以走到的状态。如果走完了这么多步都没有到终点,那就是到不了

于是直接模拟4 * n * m步就行,模拟的代码也要仔细想想,最好是用向量去写,可以让代码清晰一点。把x,y坐标分开计算。

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<int>ans;
int n, m, sx, sy, ex, ey, cnt;
int dx, dy;
bool flag = false;
string s;

void solve() {
	cin >> n >> m >> sx >> sy >> ex >> ey >> s;
	if (s[0] == 'U') dx = -1;
	else dx = 1;
	if (s[1] == 'L')dy = -1;
	else dy = 1;
	
	int total = 4 * n * m;
	while (total--) {
		if (sx == ex && sy == ey) {
			flag = true;
			break;
		}
		
		bool bouncy = false;
		if (dx == -1 && sx == 1) {
			dx = 1;
			bouncy = true;
		}
		if (dx == 1 && sx == n) {
			dx = -1;
			bouncy = true;
		}
		if (dy == -1 && sy == 1) {
			dy = 1;
			bouncy = true;
		}
		if (dy == 1 && sy == m) {
			dy = -1;
			bouncy = true;
		}
		if (bouncy)cnt++;
		sx += dx;
		sy += dy;
	}
	
	if (flag)cout << cnt << endl;
	else cout << -1 << endl;
	flag = false;
	cnt = 0;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

G1/G2. Subsequence Addition (Hard Version)(思维)

题意

起始数组为1,然后可以选几个数字出来,把他们的和再加到数组里面。问某个序列是否可以被操作出来

思路

起始为1,那就可以得到1、1。然后又可以得到1、1、2。又可以得到3,得到4……

发现每次得到的数字,不能超过前面比它小的数字的总和

比如1、1、2、3、8

假设8还没出现,目前数组是1、1、2、3,最多搞个7出来。所以这不合法

于是就可以直接给数组排序,然后遍历数组,累加总和,如果某个数字大于前面的总和,那就不合法

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<int>ans;

void solve() {
	int n; cin >> n;
	vector<long long>c(n + 1), sum(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> c[i];
	}
	sort(c.begin(), c.end());
	if (c[1] != 1) {
		cout << "NO" << endl;
		return;
	}
	bool flag = true;
	sum[1] = c[1];
	for (int i = 2; i <= n; i++) {
		sum[i] = sum[i - 1] + c[i];
		if (c[i] > sum[i - 1])flag = false;
	}
	if (flag)cout << "YES" << endl;
	else cout << "NO" << endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}
posted @ 2025-04-30 12:55  zombieee  阅读(18)  评论(0)    收藏  举报