2021/01/25补题(1400+1300+1300)

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值