Arena of Greed (CodeForces - 1425A)
题意
给出n个石子,两个人进行博弈,每个人每次可以选择拿走一个石子或拿走当前石子数目一半的石子(前提是当前石子个数为偶数),两人轮流进行,当没有石子可拿时游戏结束,问每个人都采取最优解的情况下先手最多可以拿走多少颗石子
思路
刚开始的时候以为只要每次偶数就拿一半,奇数就拿一个就是最优解,然后成功的wa掉了
一个更优的策略是:当前石子个数为4的倍数时,我们只拿一个,这样可以保证下一次对手也只能拿到一个,然后当石子个数为2的倍数且不为4的倍数时就拿走一半,因为这样对手下回合依旧只能拿一个石子。不过需要注意的一点是,当石子个数刚好为4个时,最优策略是拿走一半,这个需要特判一下
代码
#include <iostream>
using namespace std;
typedef long long LL;
int main() {
int t;
scanf("%d", &t);
while (t--) {
LL n, ans = 0;
bool flag = true;
scanf("%lld", &n);
while (n) {
if (flag) {
if (n == 4) {
ans += 2;
n -= 2;
continue;
}
if (!(n % 2) && (n % 4)) {
ans += n / 2;
n /= 2;
}
else {
ans++;
n--;
}
flag = false;
}
else {
if (n == 4) {
n -= 2;
continue;
}
if (!(n % 2) && (n % 4))
n /= 2;
else
n--;
flag = true;
}
}
printf("%lld\n", ans);
}
return 0;
}
Huge Boxes of Animal Toys (CodeForces - 1425H)
题意
有A/B/C/D四个盒子,其中每个盒子只能储存在其特定范围内的数,现在已知每个盒子内数的个数,但不知道具体数值,若可以将这些数按任意顺序相乘后变为一个数,问最终这个数可能出现在是否可能A或B或C或D中
思路
从数的个数入手,首先如果A/B盒子内的数(负数)的个数为奇数,最后所有数相乘一定是一个负数,那么就只有可能出现在A/B盒子中,否则就只有可能出现在B/C盒子中
然后再具体细分出现可以出现在那个盒子中,如果B/C盒子内的数(小于1的数)的个数不同时为0,那么不管A/D盒子内数如何,只要B/C盒子内的数足够小,一定可以将最终的结果变为一个小于1的数;同理如果A/D盒子内的数(大于1的数)的个数不同时为0,只要A/D盒子内的数足够大,一定可以将最终的结果变为一个大于1的数
代码
#include <iostream>
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int a, b, c, d;
int f[5];
for (int i = 1; i <= 4; i++) f[i] = 0;
scanf("%d%d%d%d", &a, &b, &c, &d);
if ((a + b) & 1) {
if (b || c)
f[2] = 1;
if (a || d)
f[1] = 1;
}
else {
if (b || c)
f[3] = 1;
if (a || d)
f[4] = 1;
}
for (int i = 1; i <= 4; i++)
cout << (f[i] ? "Ya" : "Tidak") << " ";
puts("");
}
return 0;
}
Years (CodeForces - 1424G)
题意
给出n个区间(左开右闭),每个区间内的点权值会自动+1,问数轴上哪个点被最多的区间覆盖,若有多个点都被同样多的区间覆盖,那么输出第一个点的位置和覆盖的区间数
思路
这是一个典型的前缀和差分问题,但是区间最大长度给到了1e9,说明无法用数组来存储每个点,并且暴力判断肯定会超时,所以我们可以只存储每个区间的端点值,因为要求的点一定在这些端点之中,然后用一个二元组给左端点同时存储端点值和+1,给右端点同时存储端点值和-1,然后遍历这些段点取最大值即可(差分)
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
const int N = 1e5 + 5;
int n;
vector<PLL> v;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
LL b, d;
scanf("%lld%lld", &b, &d);
v.push_back({b, 1});
v.push_back({d, -1});
}
sort(v.begin(), v.end());
LL sum = 0, ans = 0, k = 0, m = 2 * n;
for (int i = 0; i < m; i++) {
sum += v[i].second;
if (ans < sum) {
ans = sum;
k = v[i].first;
}
}
printf("%lld %lld\n", k, ans);
return 0;
}