题目链接
Yinchuan Regional 2019
B. So Easy
B. So Easy
题意:
初始有个 n ∗ n n*n n∗n 的数组,每一个位置都是 0 0 0。每次可以选择一行或一列,给上面的位置加 1 1 1。进行若干次操作后选择一个位置改成 − 1 -1 −1。问 − 1 -1 −1 这个位置的数是什么。
思路:
操作有点像粘胶带。每次横着或竖着贴一张宽为 1 1 1,厚度为 1 1 1 的胶带,最后得到一个 n ∗ n n*n n∗n 的厚度数组。假设 ( x , y ) (x,y) (x,y) 坐标是 − 1 -1 −1 的位置,现在变成了一张一张来撕,只留下第 x x x 行和第 y y y 列的胶带,然后两条上的胶带数量就是 − 1 -1 −1 位置的数。
用两个数组 d c [ j ] dc[j] dc[j] 和 d l [ i ] dl[i] dl[i] 分别描述第 j j j 列粘了几条胶带 和 第 i i i 行粘了几条胶带。显然如果每一列都粘了至少 x x x 个胶带的话,那么我们可以把它们看作是横着粘了 x x x 个胶带,反过来同理。所以我们不如一开始就把这些可变方向的胶带先移除掉,这样就一定会有一个位置 ( t x , t y ) (tx,ty) (tx,ty) 的厚度为 0 0 0。那么第 t x tx tx 行 和 第 t y ty ty 列一定没有贴胶带。
这时候其实 因为第 t x tx tx 行没有粘 横着的胶带,那么它的厚度就是竖着粘的胶带的条数,而且它上面的每个值一定是这个值所在列上最小的(因为其他行上都多多少少粘了胶带,厚度一定会增加),具体来说,假如厚度数组为 a [ i ] [ j ] a[i][j] a[i][j],那么 a [ t x ] [ j ] = d c [ j ] ( 1 ≤ j ≤ n ) a[tx][j]=dc[j]\quad(1\le j\le n) a[tx][j]=dc[j](1≤j≤n),并且 d c [ j ] ≤ a [ i ] [ j ] ( 1 ≤ i ≤ n ) dc[j] \le a[i][j]\quad(1\le i\le n) dc[j]≤a[i][j](1≤i≤n)。同理第 t y ty ty 列。因此第 t x tx tx 行就是我们上面定义的 d l [ i ] dl[i] dl[i] 数组,第 t y ty ty 列就是我们上面定义的 d c [ j ] dc[j] dc[j] 数组。
然后我们想,真的有必要一开始就把这些可变方向的胶带先移除掉吗,这相当于给所有位置减去 a [ i ] [ j ] a[i][j] a[i][j] 中最小的值,第 t x tx tx 行上的每个数都是它们所属列上最小的事实是没有变的。所以我们可以直接找到最小的那个数,记录 ( t x , t y ) (tx,ty) (tx,ty),先给每一行减去第 t x tx tx 行(注意别不要动第 t x tx tx 行),这时第 t y ty ty 列上的数也要减(这是因为 t x tx tx 行和 t y ty ty 列都包含上面说的可变方向的厚度,这一块是重复的,第一次减的时候给 t y ty ty 列也减一下,第二次的相减就不会重复减了),然后先给每一列减去第 t y ty ty 列(注意别不要动第 t y ty ty 列),这时第 t x tx tx 行上的数不要减(因为上面已经把重复部分减掉了,这里就不用重复减了)。这样就可以把除了第 t x tx tx 行和第 t y ty ty 列的所有位置都置为 0 0 0 了
现在把一个位置换成 − 1 -1 −1 了,该怎么办?其实也好解决。我们把 − 1 -1 −1 所在行列先隐藏不看,剩下的就可以用上面的思路求得 d l dl dl 和 d c dc dc 数组,我们把胶带都撕掉, − 1 -1 −1 所在行列上的也顺便撕掉,剩下的所有元素理应为 0 0 0。 − 1 -1 −1 所在位置也不例外,因此 − 1 -1 −1 所在位置的减完之后的值与 − 1 -1 −1 的差值就是 − 1 -1 −1 这个位置上原本的值。
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1005;
const int inf=2e9;
int n,a[maxn][maxn];
int x,y,tx,ty;
int main(){
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(!~a[i][j])x=i,y=j;
}
int minn=inf;
for(int i=1;i<=n;i++){
if(i==x)continue;
for(int j=1;j<=n;j++){
if(j==y)continue;
if(a[i][j]<minn){
minn=a[i][j];
tx=i;
ty=j;
}
}
}
for(int i=1;i<=n;i++){
if(i==tx)continue;
for(int j=1;j<=n;j++)
a[i][j]-=a[tx][j];
}
for(int j=1;j<=n;j++){
if(j==ty)continue;
for(int i=1;i<=n;i++){
if(i==tx)continue;
a[i][j]-=a[i][ty];
}
}
cout<<-1-a[x][y];
return 0;
}