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;
}

浙公网安备 33010602011771号