1451F Nullify The Matrix(博弈,异或)
Codeforces Round #685 (Div. 2)
F. Nullify The Matrix
题意:一个 n ∗ m n * m n∗m 的矩阵 m a t mat mat,元素均为非负数,其上 Ashish(先手) 与 Jeel 玩一个游戏。
每个人轮流操作的规则:
① 选择起点 S ( r 1 , c 1 ) S(r1, c1) S(r1,c1),该点元素不能为 0 0 0。
② 选择终点 T ( r 2 , c 2 ) T(r2, c2) T(r2,c2),满足 r 2 ≥ r 1 , c 2 ≥ c 1 r2 \ge r1, c2 \ge c1 r2≥r1,c2≥c1。
③ S S S 点的值减少一个任意值 x ∈ [ 1 , m a t c 1 , r 1 ] x \in [1, mat_{c1, r1}] x∈[1,matc1,r1]。
④ S S S 到 T T T 的任意一条最短路,该路上的所有点(除了 S S S)赋予任意值。
无法操作者败,给定初始局面,问胜者是谁。
范围: 1 ≤ n , m ≤ 100 , 0 ≤ m a t i , j ≤ 1 0 6 1 \le n,m \le 100,~0 \le mat_{i,j} \le 10^6 1≤n,m≤100, 0≤mati,j≤106。
分析:
通过分析可以发现起点是最重要的,如果非 0 0 0 点按照下图的对角线分布的话,每次最多只能让一个格子变成 0 0 0,本质上与 Nim 取石子是一致的,只有当 异或值不等于0 时,局面必胜,因为先手总是可以变换成 异或值等于0 的局面留给对面,而最终的败态同样为 异或值等于0。
因此通过按照对角线分割的方式我们可以将该游戏划分成 r + c − 1 r + c-1 r+c−1 个子游戏,但是本题中他们不是相互独立的。
而题目提供的修改操作是在起点到终点的最短路上进行的,我们可以在路上进行任意赋值,意味着我们可以对其间的所有子游戏进行胜负态变换,以此来完成整体的胜负态变换。
因此操作允许我们将当前的局面 S S S:存在子游戏异或和非0 进行一次移动后变成局面 S ′ S' S′:所有子游戏异或和均为0,并且局面 S ′ S' S′ 进行一次移动必然会变换为局面 S S S,且最终败态为 S ′ S' S′,因此根据起始局面是否为 S S S 即可判断胜负态。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 100 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
int arr[MAXN][MAXN];
int xorsum[MAXN * 2];
signed main()
{
int T = read();
while (T--)
{
memset(xorsum, 0, sizeof(xorsum));
n = read(), m = read();
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
arr[i][j] = read();
xorsum[i + j] ^= arr[i][j];
}
}
int ans = 0;
for (int i = 0; i < n + m; i++)
{
if (xorsum[i])
{
ans = 1;
break;
}
}
if (ans)
{
cout << "Ashish" << endl;
}
else
{
cout << "Jeel" << endl;
}
}
return 0;
}
【END】感谢观看