Gojou and Matrix Game(dp,推式子)

本文介绍了一个名为GojouandMatrixGame的问题,这是一个关于两位玩家在矩阵中进行的游戏。文章详细解释了游戏规则,并提出了一种通过排序和维护特定值来优化解决方案的方法,最终实现了O(n²)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gojou and Matrix Game

[Link](Problem - E - Codeforces)

题意

M M M G G G在一个 n × n n\times n n×n的二维矩阵中玩游戏,矩阵中每个位置元素值都不同,一共 n × n n\times n n×n局游戏, M M M每次从没有开局过的位置开始游戏,两个人依次加上选取位置上的值,但要满足当前选取的位置与上一次选取的位置的曼哈顿距离大于 k k k(除第一个人外),每局游戏一共选取 1 0 100 10^{100} 10100次,请你输出 M M M从每个位置开局的结果。

思路

​ 假设 M M M选了 x x x下一次 G G G选了 y y y,且 x > y x >y x>y M M M必胜,因为 M M M G G G选完后还可以一直选 x x x,会一直扩大自己的优势,所以 M M M从值最大的格子开局必胜,设 f [ i ] [ j ] : ( i , j ) 这 个 格 子 必 胜 还 是 必 败 f[i][j]:(i,j)这个格子必胜还是必败 f[i][j]:(i,j)

​ 因为每个格子只会和权值比他大的格子产生关系所以我们将所有的格子按照权值从大到小排序,对于第 k k k个格子 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)来说如果它能到某个必胜的格子则必败,因为下一个人就可以选那个格子了。因此我们需要判断第 k k k个格子前面所有必胜的格子是否曼哈顿距离大于 k k k,暴力存取的话复杂度为 O ( n 4 ) O(n^4) O(n4) T T T了。

​ 考虑一下数学式子,对于 ( x 1 , y 1 ) 和 ( x 2 , y 2 ) (x_1,y_1)和(x_2,y_2) (x1,y1)(x2,y2)我们要检察 a b s ( x 1 − x 2 ) + a b s ( y 1 − y 2 ) > k abs(x_1-x_2)+abs(y_1-y_2)>k abs(x1x2)+abs(y1y2)>k,有四种情况:

  • 左边 > 0 >0 >0,右边 > 0 >0 >0 x 1 − x 2 + y 1 − y 2 > k → ( x 1 + y 1 ) − ( x 2 + y 2 ) > k x_1-x_2+y_1-y_2>k\to(x_1+y_1)-(x_2+y_2)>k x1x2+y1y2>k(x1+y1)(x2+y2)>k

  • 左边 < 0 <0 <0,右边 < 0 <0 <0 x 2 − x 1 + y 2 − y 1 > k → − ( ( x 1 + y 1 ) − ( x 2 + y 2 ) ) > k x_2-x_1+y_2-y_1>k\to-((x_1+y_1)-(x_2+y_2))>k x2x1+y2y1>k((x1+y1)(x2+y2))>k

  • 左边 > 0 >0 >0,右边 < 0 <0 <0 x 1 − x 2 + y 2 − y 1 > k → ( x 1 − y 1 ) − ( x 2 + y 2 ) > k x_1-x_2+y_2-y_1>k\to(x_1-y_1)-(x_2+y_2)>k x1x2+y2y1>k(x1y1)(x2+y2)>k

  • 左边 < 0 <0 <0,右边 < 0 <0 <0 x 2 − x 1 + y 1 − y 2 > k → − ( ( x 1 − y 1 ) − ( x 2 + y 2 ) ) > k x_2-x_1+y_1-y_2>k\to-((x_1-y_1)-(x_2+y_2))>k x2x1+y1y2>k((x1y1)(x2+y2))>k

发现 a b s ( x 1 − x 2 ) + a b s ( y 1 − y 2 ) > k ⇔ m a x ( a b s ( ( x 1 + y 1 ) − ( x 2 + y 2 ) ) , a b s ( ( x 1 − y 1 ) − ( x 2 + y 2 ) ) ) > k abs(x_1-x_2)+abs(y_1-y_2)>k\Leftrightarrow max(abs((x_1+y_1)-(x_2+y_2)),abs((x_1-y_1)-(x_2+y_2)))>k abs(x1x2)+abs(y1y2)>kmax(abs((x1+y1)(x2+y2)),abs((x1y1)(x2+y2)))>k,因此我们维护一下合法的 x + y x+y x+y x − y x-y xy的最大最小值即可复杂度 O ( n 2 ) O(n^2) O(n2)

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
void solve() {
    cin >> n >> k;
    vector<array<int, 5>> g(n * n);
    vector<vector<bool>> f(n + 1, vector<bool>(n + 1, false));
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++) {
            int x; cin >> x;
            g.push_back({x, i, j, i + j, i - j});
        }

    sort(g.begin(), g.end(), [&](array<int, 5> a, array<int, 5> b) {
        return a[0] > b[0];
    });

    vector<int> c(4);
    function<bool(int , int )> check = [&](int x, int y) {
        if (abs(x + y - c[0]) > k || abs(x + y - c[1]) > k || abs(x - y - c[2]) > k || abs(x - y - c[3]) > k) return false;
        return true;
    };
 
    f[g[0][1]][g[0][2]] = true; c[0] = c[1] = g[0][3], c[2] = c[3] = g[0][4];
    for (int i = 1; i < n * n; i ++) {
        if (check(g[i][1], g[i][2])) {
            f[g[i][1]][g[i][2]] = true;
            c[0] = max(c[0], g[i][3]);
            c[1] = min(c[1], g[i][3]);
            c[2] = min(c[2], g[i][4]);
            c[3] = max(c[3], g[i][4]);
        }
    }

    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++)
            cout << (f[i][j] ? 'M' : 'G');
        cout << '\n';
    }

}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T = 1;
   // cin >> T;
    while (T -- ) {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值