A. 决斗时刻到了
https://codeforces.com/contest/2109/problem/A
时间限制: 1 秒
内存限制: 256 兆字节
输入: 标准输入
输出: 标准输出
关于 Mouf,你可能不知道他是游戏王卡牌游戏的忠实粉丝。他喜欢和任何人决斗。为了召集所有喜欢玩游戏的粉丝,他决定组织一次大型游戏王锦标赛,并邀请了 n n n 名玩家参加。
Mouf 将 n n n 名玩家排成一排,从 1 1 1 到 n n n 依次编号。然后他们连续进行了 n − 1 n - 1 n−1 次对决:从 1 1 1 到 n − 1 n - 1 n−1 的每一个 i i i,棋手 i i i 对阵棋手 i + 1 i + 1 i+1,每场比赛产生一个赢家和一个输家。之后,每个棋手都会报告一个值 a i a_i ai ( 0 ≤ a i ≤ 1 0 \le a_i \le 1 0≤ai≤1):
- 0 0 0 表示他们没有赢得决斗;
- 1 1 1 表示他们至少赢了一场决斗。
由于有些人可能会谎报自己的结果(例如,报告的是 1 1 1 而不是 0 0 0,反之亦然)以影响奖金结果,因此如果穆夫能证明任何报告是假的,他就会取消比赛。
给定数组 a a a,判断是否至少有一名棋手在说谎。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t t t ( 1 ≤ t ≤ 100 1 \le t \le 100 1≤t≤100)。测试用例说明如下。
每个测试用例的第一行都包含一个整数 n n n ( 2 ≤ n ≤ 100 2 \le n \le 100 2≤n≤100) - 锦标赛的参赛人数。
每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an ( 0 ≤ a i ≤ 1 0 \le a_i \le 1 0≤ai≤1) --表示 i i i-th 玩家的报告。
输出
对于每个测试用例,如果参与者中至少有一个说谎者,则打印 “是”(不带引号),否则打印 “否”(不带引号)。
您可以用任何大小写(大写或小写)输出答案。例如,字符串 “yEs”、“yes”、"Yes "和 "YES "将被识别为肯定回答。
解题思路
这道题目需要判断玩家是否在报告比赛结果时撒谎。关键点在于:
- 每个玩家要与相邻的玩家比赛一次
- 如果一个玩家报告0,表示他没赢过任何比赛
- 如果一个玩家报告1,表示他至少赢过一次比赛
判断逻辑:
- 如果所有玩家都报告1,一定有人撒谎(因为不可能没有人输)
- 如果所有玩家都报告0,同样明显撒谎(因为一定有赢家)
- 如果有两个相邻的玩家都报告0,那么至少有一人在撒谎(因为他们必须对战,必有一人获胜)
- 若上述条件都不满足,则存在一种排列使得报告是真实的
AC Code
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> a(n);
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
if (a[i] == 1) {
cnt1++;
} else {
cnt2++;
}
}
if (cnt1 == 0 || cnt2 == 0) {
cout << "YES" << endl;
return;
}
for (int i = 0; i < n - 1; ++i) {
if (a[i] == 0 && a[i + 1] == 0) {
cout << "YES" << endl;
return;
}
}
cout << "NO" << endl;
}
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B. 切片生存
https://codeforces.com/contest/2109/problem/B
时间限制: 1 秒
内存限制: 256 兆字节
输入: 标准输入
输出: 标准输出
决斗者 Mouf 和 Fouad 进入竞技场,这是一个 n × m n \times m n×m 格!
法德的怪物从 ( a , b ) (a, b) (a,b) 单元格开始,其中行的编号为 1 1 1 至 n n n,列的编号为 1 1 1 至 m m m。
毛夫和法德将一直对决,直到网格中只剩下一个单元格。
在每个回合中:
- 穆夫首先沿着一行或一列将网格切成两部分,然后丢弃没有法德怪物的部分。注意,网格必须至少有两个单元格,否则游戏已经结束。
- 然后,在同一回合中,法德将他的怪物移动到剩余网格中的任何一个单元格(可能是它原来所在的单元格)。
第四个测试案例的可视化阶段。
穆夫希望尽量减少回合数,而法德则希望尽量增加回合数。如果双方都发挥出最佳水平,这场史诗般的对决将持续多少回合?
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104)。测试用例说明如下。
每个测试用例的第一行也是唯一一行包含四个整数 n n n、 m m m、 a a a 和 b b b ( 2 ≤ n , m ≤ 1 0 9 2 \le n, m \le 10^9 2≤n,m≤109, 1 ≤ a ≤ n 1 \le a \le n 1≤a≤n, 1 ≤ b ≤ m 1 \le b \le m 1≤b≤m),分别表示行数、列数、怪物的起始行和怪物的起始列。
输出
对于每个测试用例,输出一个整数——如果双方都发挥出最佳水平,这场史诗对决将持续的回合数。
解题思路
我们需要模拟网格被逐步分割的过程,计算出最优策略下的回合数。
分析
问题分解
- 每次切割将网格分成两部分,保留包含怪物的部分。
- 玩家会移动怪物到剩余网格的任意位置,以最大化回合数。
最优策略
- 穆夫希望最小化回合数,因此每次切割应尽可能将网格分成较小的部分。
- 法德希望最大化回合数,因此会移动怪物到剩余部分中间位置。
模拟过程
- 计算每次切割后网格的大小,并记录切割次数。
- 使用递归或循环模拟切割过程,直到网格缩小到 1x1。
算法步骤
- 计算在行和列方向上的最佳切割策略(因为初始时需要根据怪物的位置进行切割,之后的切割怪物可以随意移动,只需要一开始时考虑即可)。
- 分别计算从行和列开始的最佳切割次数。
- 取这两个方向中的最小值作为最终结果。
AC Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll cal(ll r, ll c) {
ll res = 0;
while (r > 1 || c > 1) {
res++;
if (r == 1) {
c = (c + 1) / 2;
} else if (c == 1) {
r = (r + 1) / 2;
} else {
if (r >= c) {
r = (r + 1) / 2;
} else {
c = (c + 1) / 2;
}
}
}
return res;
}
void solve() {
ll n, m, a, b;
cin >> n >> m >> a >> b;
ll row = min(a, n - a + 1);
ll row1 = 1 + cal(row, m);
ll col = min(b, m - b + 1);
ll col1 = 1 + cal(n, col);
cout << min(row1, col1) << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}