IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Codeforces Round #779 (Div. 2) E. Gojou and Matrix Game -> 正文阅读

[C++知识库]Codeforces Round #779 (Div. 2) E. Gojou and Matrix Game

E. Gojou and Matrix Game

在这里插入图片描述
这里我们定义一次(先手,后手)为一轮游戏,因为进行 1 0 100 10^{100} 10100 次,所以可以进行整数轮游戏。

首先我们可以发现如果先手站在最大值上直接就赢了,因为后手无论走哪个点,先手又可以回来取最大点,所以每一轮先手都可以比后手优,所以必胜。

然后我们考虑先手初始在非最大值的情况,我们可以发现,如果先手站在非最大值上,假设这个值是 v v v ,那么后手下一步必须走到 > v >v >v 的点,为何呢,如果后手不这么做,选了一个 < v <v <v 的点,先手下一次又可以选回 v v v ,本身我后手第一轮我就亏了,然后还回到了与上一轮一样的情况(先手选了 v v v ),说白了我白亏一轮,所以后手不可能白亏,所以他必定会选 > v >v >v 的点。

那么我们发现,我们可以按 v v v 值倒序遍历,递推每个点的答案。这里我们设 f [ x ] [ y ] f[x][y] f[x][y] 表示初始站在 ( x , y ) (x,y) (x,y) 点的胜败态, f [ x ] [ y ] = 0 f[x][y]=0 f[x][y]=0 为败, f [ x ] [ y ] = 1 f[x][y]=1 f[x][y]=1 为胜。

那么我们已知 v [ x ] [ y ] v[x][y] v[x][y] m a x max max 时, f [ x ] [ y ] = 1 f[x][y]=1 f[x][y]=1

假设当前遍历到 ( x , y ) (x,y) (x,y) ,那么后手只有到达点 ( x 1 , y 1 ) (x_1,y_1) (x1?,y1?) 满足 v [ x 1 ] [ y 1 ] > v [ x ] [ y ] v[x_1][y_1]>v[x][y] v[x1?][y1?]>v[x][y] f [ x 1 ] [ y 1 ] = 1 f[x_1][y_1]=1 f[x1?][y1?]=1 才能赢,因为我们是倒序遍历,所以比 v [ x ] [ y ] v[x][y] v[x][y] 值大的点,且是胜利态的点 ( x 1 , y 1 ) (x_1,y_1) (x1?,y1?) 我们是已经得到了的,那么 ( x , y ) (x,y) (x,y) 能走到 ( x 1 , y 1 ) (x_1,y_1) (x1?,y1?) 的条件是 :
∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ > k |x-x_1|+|y-y_1|>k x?x1?+y?y1?>k
那么只要存在一个满足上述条件的点 ( x 1 , y 1 ) (x_1,y_1) (x1?,y1?) 后手即可获胜,这里我们可以反过来求,如果所有 ( x 1 , y 1 ) (x_1,y_1) (x1?,y1?) 都满足:
∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ ≤ k |x-x_1|+|y-y_1|\leq k x?x1?+y?y1?k
那么即后手没有机会赢,先手必胜,反之先手必败。

那么我们将式子做一个转换:
∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ = m a x ( ∣ ( x + y ) ? ( x 1 + y 1 ) ∣ , ∣ ( x ? y ) ? ( x 1 ? y 1 ) ∣ ) |x-x_1|+|y-y_1|=max(|(x+y)-(x_1+y_1)|,|(x-y)-(x_1-y_1)|) x?x1?+y?y1?=max((x+y)?(x1?+y1?),(x?y)?(x1??y1?))

这里粗略的证明一下上述公式, ∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ |x-x_1|+|y-y_1| x?x1?+y?y1? 把绝对值拆开只可能产生四个式子:
( x + y ) ? ( x 1 + y 1 ) (x+y)-(x_1+y_1) (x+y)?(x1?+y1?)
( x 1 + y 1 ) ? ( x + y ) (x_1+y_1)-(x+y) (x1?+y1?)?(x+y)
( x ? y ) ? ( x 1 ? y 1 ) (x-y)-(x_1-y_1) (x?y)?(x1??y1?)
( x 1 ? y 1 ) ? ( x ? y ) (x_1-y_1)-(x-y) (x1??y1?)?(x?y)

这里设 ① = ∣ x ? x 1 ∣ ①=|x-x_1| =x?x1? ② = ∣ y ? y 1 ∣ ②=|y-y_1| =y?y1? ∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ |x-x_1|+|y-y_1| x?x1?+y?y1? 正确的答案应该是 ① + ② ①+② + ,而在上述把绝对值拆开的四个等式中倘若不是正确的值,则只可能是 ① ① ② ② 取了负号,那么答案一定会变小,所以正确的值一定是上述四个式子中最大的一个。那么再将上述四个式子两两合并写一下就是:

∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ = m a x ( ∣ ( x + y ) ? ( x 1 + y 1 ) ∣ , ∣ ( x ? y ) ? ( x 1 ? y 1 ) ∣ ) |x-x_1|+|y-y_1|=max(|(x+y)-(x_1+y_1)|,|(x-y)-(x_1-y_1)|) x?x1?+y?y1?=max((x+y)?(x1?+y1?),(x?y)?(x1??y1?))
证毕

因此我们最终可以得到:
∣ x ? x 1 ∣ + ∣ y ? y 1 ∣ ≤ k ?? ? ?? m a x ( ∣ ( x + y ) ? ( x 1 + y 1 ) ∣ , ∣ ( x ? y ) ? ( x 1 ? y 1 ) ∣ ) ≤ k |x-x_1|+|y-y_1|\leq k \iff max(|(x+y)-(x_1+y_1)|,|(x-y)-(x_1-y_1)|) \leq k x?x1?+y?y1?k?max((x+y)?(x1?+y1?),(x?y)?(x1??y1?))k
所以我们只要维护 ( x 1 + y 1 ) (x_1+y_1) (x1?+y1?) ( x 1 ? y 1 ) (x_1-y_1) (x1??y1?) 分别的最大和最小值,这样我们就可以知道上述式子是否成立,若成立则 f [ x ] [ y ] = 0 f[x][y]=0 f[x][y]=0 ,否则 f [ x ] [ y ] = 1 f[x][y]=1 f[x][y]=1 。若 f [ x ] [ y ] = 1 f[x][y]=1 f[x][y]=1 则需要更新最小和最大值。

#include<bits/stdc++.h>

using namespace std;

const int N = 2e3 + 10;

struct node {
    int x;
    int y;
    int v;
    bool operator < (const node &t) {
        return v > t.v;
    }
};
int n, k;
bool f[N][N];
vector<node> a;

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            int v; scanf("%d", &v);
            a.push_back({i, j, v});
        }
    }
    sort(a.begin(), a.end());
    f[a[0].x][a[0].y] = 1;
    int mn_xaddy, mn_xsuby, mx_xaddy, mx_xsuby;
    mn_xaddy = mx_xaddy = a[0].x + a[0].y;
    mn_xsuby = mx_xsuby = a[0].x - a[0].y;
    for (int i = 1; i < n * n; ++i) {
        int x = a[i].x, y = a[i].y;
        // if (a[i].v == 10) {
        //     cout << max({abs(x+y-mn_xaddy), abs(x+y-mx_xaddy), abs(x-y-mn_xsuby), abs(x-y-mx_xsuby)}) << endl;
        // }
        if (max({abs(x+y-mn_xaddy), abs(x+y-mx_xaddy), abs(x-y-mn_xsuby), abs(x-y-mx_xsuby)}) <= k) {
            f[x][y] = 1;
            mn_xaddy = min(mn_xaddy, x+y);
            mx_xaddy = max(mx_xaddy, x+y);
            mn_xsuby = min(mn_xsuby, x-y);
            mx_xsuby = max(mx_xsuby, x-y);
        }
        else {
            f[x][y] = 0;
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            printf("%c", f[i][j] == 1 ? 'M' : 'G');
        }
        puts("");
    }
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:05:26  更:2022-03-30 18:08:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:51:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码