目录
A. Chip Game
题意:两个人在一个n * m 的网格的左下角进行操作,只可以进行两种操作:向上走或者向右走并且每次移动只可以移动奇数个格子,其中Burenka先走,然后是Tonya走,判断谁可以移动到队首无法移动的位置,谁胜
思路:根据规则可以找到最后一个人操作之后的格子是到网格中右上角的格子,由于限制了移动规则,所以两人最后走过的路程总和为 (n - 1 + m - 1)个格子,每个人都是使用最优的移动策略,可以很明显的看出他们的胜利和(n + m + 2)的奇偶性有关(虽然很容易通过样例看出来,但是还是需要证明一下的)
当n和m都是偶数时: 所以(n + m - 2)是偶数,对于两条边分别是奇数,由于移动的距离必须是奇数,对于向右移动时,一定是先手(Burenka)先到达【1, m】,之后的向上操作先手(Burenka)变成了后手,后手(Tonya)变成了先手移动,之后的总距离是奇数,所以一定是先手(Tonya)到达,同理四种情况可以被(n + m - 2)分成两种
1、(n + m - 2)奇数 ——Burenka胜
2、 (n + m - 2) 偶数 ——Tonya胜
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int t;
cin >> t;
int a, b;
while (t -- ) {
cin >> a >> b;
ll ans = a + b;
if(ans & 1) {
printf("Burenka\n");
}
else {
printf("Tonya\n");
}
}
return 0;
}
B. Mathematical Circus
题意:给定n 和 k, 从1 - n的数中(n确保是偶数)分别拿出两个数a 和 b,使得其满足(a + k)* b可以被4整除(取余于4余数是0)
思路:
在1 - n数中进行那,证明数可以重复使用
根据k % 4进行分类
1、当k == 0时,式子为 a*b 使得其可以被4整除,可以看出,无法实现,1 - n中偶数占一半,4的倍数又是偶数的一半(带不动所以的奇数),无法使得所有数组合成a * b均满足被4整除
2、当k == 2时,1——n可以分为每四个数中会产生一个4的倍数假设这个数是i,那么可以将i-2通过加 k 使其成为4的倍数,他就可以和 i - 3组合,成为一组正确的组合
3、当k == 1是,由于每4个数可以产生一个4的倍数(从一依次算起), k = 1是,起就可以使得i-1变成4的倍数,从而可以和 i - 2 或者1 - 3进行组合,与 i 组合的数让 i 当做b,既可以满足
4、当k == 3的时候,思路与上面相同
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, k;
scanf("%d%d", &n, &k);
if(k % 4 == 0) printf("NO\n");
else if(k % 2 == 1) {
printf("YES\n");
for (int i = 0; i + 4 <= n; i += 4) {
printf("%d %d\n", i + 1, i + 2);
printf("%d %d\n", i + 3, i + 4);
}
if(n % 4 == 2) {
printf("%d %d\n", n - 1, n);
}
}
else if(k % 4 == 2) {
printf("YES\n");
for (int i = 0; i + 4 <= n; i += 4) {
printf("%d %d\n", i + 1, i + 4);
printf("%d %d\n", i + 2, i + 3);
}
if(n % 4 == 2) {
printf("%d %d\n", n, n - 1);
}
}
}
int main() {
int t;
scanf("%d", &t);
while (t -- ) {
solve();
}
return 0;
}
C. Fighting Tournament
题意:一个数组,第 i 个数表示第 i 个人的战斗,战斗方式是依次战斗,数组中的前两个进行战斗,获胜的留在前面,失败的人回到队尾
思路:可以看出数组数组中存在一个数(max最大值)在一定的轮数后是一直赢得,想用达到这个轮数后,其他人之后就再也不回赢,最坏的情况是最大值起初位于队尾,所以最多进行n - 1轮之后进入“独孤求败”阶段,所以通过n - 1次模拟处理出,(题目中规定了,每个人的战斗力都不一样)
代码(注释上了解释) :
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int a[N];
int n, q;
int c[N], b[N], d[N];
//c[]记录每个人赢了多少次
//b[]记录每个人第一次什么时候赢得
//d[]记录轮是谁赢了
void solve() {
cin >> n >> q;
for (int i = 1; i <= n; i ++ ) {
scanf("%d", &a[i]);
b[i] = c[i] = 0;
}
int temp = a[1];
for (int i = 2; i <= n; i ++ ) {
if(temp < a[i]) temp = a[i];//找到每次比试获胜的那个人
c[temp] ++ ;//记录每个人赢了多少次
if(b[temp] == 0) b[temp] = i - 1;//记录这个人第一次的轮次
d[i - 1] = temp;//记录这一轮是谁赢了
}
while (q -- ) {
int x, k;
scanf("%d%d", &x, &k);
x = a[x];
int ans = 0;
if(k <= n - 1) {
//只有两者中最大可以留下,所以当走过这一轮之后,d[k]的数一定大于等于x
if(d[k] < x) {
ans = 0;
}
else if(d[k] == x) {
//正好访问的真是这一轮时,所以从一开始赢也就是b[x]
//记录的位置,到现在的位置一直都是这个人赢得
ans = k - b[x] + 1;
}
else {
//这个人已经不可能在赢了,直接输出统计数即可
ans = c[x];
}
}
else {
//最多走一轮就可以让最大值到第一位,之后只有是最大值可以赢
ans = c[x] + (x == n ? k - n + 1: 0);
}
printf("%d\n", ans);
}
}
int main() {
int t;
cin >> t;
while (t -- ) {
solve();
}
return 0;
}
由于我比较菜,目前只具备div2前3题或者前2题的水平,慢慢进步吧!