首页 > 其他分享 >P7515 [省选联考 2021 A 卷] 矩阵游戏 题解

P7515 [省选联考 2021 A 卷] 矩阵游戏 题解

时间:2024-08-24 21:09:19浏览次数:12  
标签:P7515 int 题解 矩阵 kMaxN leq le 联考 dis

Description

Alice 有一个 \(n \times m\) 的矩阵 \(a_{i, j}\)(\(1 \le i \le n\),\(1 \le j \le m\)),其每个元素为大小不超过 \({10}^6\) 的非负整数。

Bob 根据该矩阵生成了一个 \((n - 1) \times (m - 1)\) 的矩阵 \(b_{i, j}\)(\(1 \le i \le n - 1\),\(1 \le j \le m - 1\)),每个元素的生成公式为

\[b_{i, j} = a_{i, j} + a_{i, j + 1} + a_{i + 1, j} + a_{i + 1, j + 1} \]

现在 Alice 忘记了矩阵 \(a_{i, j}\),请你根据 Bob 给出的矩阵 \(b_{i, j}\) 还原出 \(a_{i, j}\)。

\(2 \le n, m \le 300\),\(0 \le b_{i, j} \le 4 \times {10}^6\)。

Solution

首先有个显然的事实是只要确定了第一行和第一列的值就能确定整个矩阵。

那么可以先在第一行和第一列随便填数,这时可能会有些数不在限制里面,考虑调整。

注意到让一行或一列进行类似 \(-x,+x,-x,+x\ldots-x,+x\) 的操作后仍然满足 \(b\) 矩阵的性质,不妨设 \(x\) 为偏移量。

考虑只做这类操作,设 \(x_i\) 为第 \(i\) 行的偏移量,\(y_i\) 为第 \(i\) 列的偏移量。

那么对于每个 \((i,j)\),一定满足 \(0\leq a_{i,j}+(-1)^jx_i+(-1)^iy_j\leq 10^6\)。可以设 \(b_i=(-1)^ix_i,c_i=(-1)^{i+1}y_i\),那么就是 \(0\leq (-1)^{i+j}b_i-(-1)^{i+j}c_j\leq 10^6\),这是个差分约束的形式,可以 spfa 求解。无解就等价于出现了负环。

下面证明一下通过上面所述的操作一定可以操作出任意符合条件的矩形:

由于只要确定了第一行和第一列的值就可以确定整个矩阵,所以可以先把行操作做完再做列操作,容易发现这样第一行第一列的数可以取到任意值,也就是说这样做可以构造出任意一个符合条件的矩阵。

时间复杂度:\(O(n^3)\)。

Code

#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 305;

int n, m;
int a[kMaxN][kMaxN], b[kMaxN][kMaxN], dis[kMaxN * 2], cnt[kMaxN * 2];
bool inq[kMaxN * 2];
std::vector<std::pair<int, int>> G[kMaxN * 2];

bool spfa() {
  std::queue<int> q;
  for (int i = 1; i <= n + m; ++i)
    dis[i] = 1e9, cnt[i] = inq[i] = 0;
  q.emplace(1), dis[1] = 0, inq[1] = 1;
  for (; !q.empty();) {
    int u = q.front(); q.pop();
    inq[u] = 0;
    for (auto [v, w] : G[u]) {
      if (dis[v] > dis[u] + w) {
        dis[v] = dis[u] + w;
        if (!inq[v]) q.emplace(v), inq[v] = 1;
        if (++cnt[v] == n + m) return 0;
      }
    }
  }
  return 1;
}

void dickdreamer() {
  std::cin >> n >> m;
  for (int i = 1; i <= n + m; ++i) G[i].clear();
  for (int i = 1; i < n; ++i)
    for (int j = 1; j < m; ++j)
      std::cin >> b[i][j];
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      if (i == 1 || j == 1) a[i][j] = 0;
      else a[i][j] = b[i - 1][j - 1] - a[i - 1][j - 1] - a[i - 1][j] - a[i][j - 1];
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      int L = -a[i][j], R = 1e6 - a[i][j];
      if ((i + j) & 1) std::swap(L, R), L = -L, R = -R;
      G[i].emplace_back(j + n, -L), G[j + n].emplace_back(i, R);
    }
  }
  if (!spfa()) return void(std::cout << "NO\n");
  std::cout << "YES\n";
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      int op = ((i + j) % 2 ? -1 : 1);
      std::cout << a[i][j] + dis[i] * op - dis[j + n] * op << ' ';
    }
    std::cout << '\n';
  }
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:P7515,int,题解,矩阵,kMaxN,leq,le,联考,dis
From: https://www.cnblogs.com/Scarab/p/18378239

相关文章

  • VS2022 Visual Studio Installer 一直卡在0%,或者下载速度慢的问题解决办法
    C:\Users\Administrator\AppData\Local\Temp到c盘查看日志,发现是下载一个叫vs_installer.opc的东西失败了, 直接复制日志里的https://aka.ms/vs/17/release/installer,下载,发现成功下载,然后放到installer安装器同级目录,重新打开setup安装,就成功了打开了,然后会一直正在准备中,......
  • P10933 创世纪 题解
    题目传送门前置知识树形DP解法将\(a_{i}\)向\(i\)连一条有向边,这样就形成了基环外向树森林。设\(f_{x,0/1}\)表示\(x\)不选/选时,以\(x\)为根的子树的最多选择个数,状态转移方程为\(\begin{cases}f_{x,0}=\sum\limits_{y\inSon(x)}\max(f_{y,0},f_{y,1})\\f_......
  • P10957 环路运输 题解
    题目传送门前置知识单调队列/单调栈优化解法在仓库\(1\)和\(n\)之间把环断开,然后复制一倍接在末尾,形成长度为\(2n\)的直线公路,即有\(a_{i}=a_{i+n}(1\lei\len)\)。对于原来环形公路上的任意两座仓库\(i,j(1\lej<i\len)\),代价为\(\begin{cases}a_{i}+a_{j}......
  • Chain Contestant 题解
    前言题目链接:洛谷;AtCoder。最慢的点才跑\(2\)ms的题解确定不看一看?题意简述给定长度为\(n\)的字符串\(s\),其中\(s_i\in\Omega\),求有多少子序列\(T\)满足任意\(x\in\Omega\),其在\(T\)出现的位置为连续一段,当然,对\(998244353\)取模。\(n\leq10^5\),\(|\Omeg......
  • P3547 [POI2013] CEN-Price List 题解
    Description给定一个\(n\)个点\(m\)条边的无向图,边权均为\(a\)。现在将原来图中满足最短路等于\(2a\)所有的点对\((x,y)\)之间加一条长度为\(b\)的无向边。给定\(k\),求点\(k\)到所有点的最短路是多少。\(1\leqn,m\leq10^5\)。Solution首先有个显然的结论是......
  • 洛谷P2440 木材加工 题解
    这是我找到的一篇很久之前为了让我更好理解二分写的详细题解题目链接code:#include<bits/stdc++.h>#defineintlonglong#defineMAXN0x3f3f3f3f3f3f3f3f#defineMINN-0x3f3f3f3f3f3f3f3f#defineMiraiios::sync_with_stdio(0),cin.tie(0),cout.tie(0);usingnamespa......
  • CF939F Cutlet题解
    前置单调队列(没学过或忘了点这里)简化题意有一块牛排,要求对它烹饪\(2n\)秒,可在给定的\(k\)个时间段中将它翻转任意次,使得牛排两面都受到了\(n\)秒的烹饪。状态设计可以发现当总共煮了\(i\)秒,其中一面如果煮了\(j\)秒,自然可以求出另一面为\(i-j\)秒,所以我们可以......
  • CSP 2023 提高级第一轮 CSP-S 2023初试题 程序阅读第三题解析
    一、程序阅读#include<vector>#include<algorithm>#include<iostream>usingnamespacestd;boolf0(vector<int>&a,intm,intk){ints=0;for(inti=0,j=0;i<a.size();i++){while(a[i]-a[j]>......
  • P10690 Fotile 模拟赛 L 题解
    题目传送门前置知识可持久化字典树|分块思想解法考虑分块预处理整块的答案,散块直接暴力。设\(f_{i,j}\)表示以\(i\)所在的块的左端点为左端点,\(j\)为右端点的最大异或和,可持久化01-Trie维护即可。本题中这种写法比处理整块到整块的答案更容易处理些。整块的答案......
  • 讨论TableLayoutPanel加载缓慢和闪烁问题解决方案
    WinForm加载多个自定义控件时,会出现很严重的闪烁问题,很卡,一块一块的加载(像打开网页时,网络很卡的那种感觉)简直没法忍受。在网上搜索了好久,网上大部分的方法是一下4种,但是都不能有效的解决问题。1、将DoubleBuffered设置true,用双缓存处理Form界面内容加载,可以提高页面显......