题目传送门

题意:

有一个 \(n \times m\) 的矩阵,里面已经填好了 \(k\) 个非负整数。

问是否能在其它 \(n \times m-k\) 个格子里各填上一个非负整数,使得得到的矩阵满足以下条件:

  • 在任意一个 \(2 \times 2\) 的子矩阵中,左上角的数 \(+\) 右下角的数 \(=\) 右上角的数 \(+\) 左下角的数。

如果可以输出 Zibi 否则输出 Zikai

\(n,m,k \in [1,10^5]\)

考虑探究这个矩阵有什么性质。假设有一个 \(3 \times 3\) 的子矩阵:

\[\begin{bmatrix}a&d&g\\b&e&h\\c&f&i\end{bmatrix}
\]

根据上面的条件我们有:

\[\begin{cases}a+e=b+d\\b+f=c+e\\d+h=e+g\\e+i=f+h\end{cases}
\]

由第一个和第三个式子可以得到 \(a+f=g+c\)

由第二个和第四个式子可以得到 \(d+i=g+f\)

再把这两个式子相结合一下可以得到 \(a+i=c+d\)

于是我们初步得到一个结论:如果有个满足条件的矩阵 \(A\),那么对于任意 \(x_1,x_2 \in [1,n],y_1,y_2 \in [1,m],x_1 \neq x_2,y_1 \neq y_2\),都有

\[A_{x_1,y_1}+A_{x_2,y_2}=A_{x_1,y_2}+A_{x_2,y_1}
\]

根据这个性质,考虑固定住第一行和第一列,根据上面的性质填好剩下 \((n-1)\times(m-1)\) 个数。

那么显然有 \(A_{i,j}=A_{1,j}+A_{i,1}-A_{1,1}\)

我们令 \(r_1=0,r_i(i>2)=A_{i,1}-A_{1,1}\)。

再令 \(c_i=A_{1,i}\)。

那么对于任意 \(i \in [1,n],j \in [1,m]\),你把 \(r_i+c_j\) 计算出来就会得到 \(A_{i,j}=r_i+c_j\)

现在我们的目标是找出是否存在满足条件的 \(r_i,c_i\)

我们假设同一行中有两个已经填好的数 \(A_{i,y_1}=v_1,A_{i,y_2}=v_2\)。

那么 \(v_1=r_i+c_{y_1},v_2=r_i+c_{y_2}\)。

两式相减可以得到 \(c_{y_1}-c_{y_2}=v_1-v_2\)。

在顶点 \(y_1,y_2\) 之间连一条有向边边,边权为 \(v_1-v_2\)。

这样建边看似是 \(n^2\) 的,不过注意到如果已知 \(c_{y_1}-c_{y_2}=v_1-v_2,c_{y_1}-c_{y_3}=v_1-v_3\),就可以直接得出 \(c_{y_2}-c_{y_3}=v_2-v_3\),所以可以把第 \(i\) 行填好数的位置按列数从小到大排序,只用在相邻顶点之间建边,这样边数最多是 \(\mathcal O(n)\) 的。

然后你对于每个连通块进行一遍 \(dfs\),求出该连通块中编号最小的点 \(x\) 到每个点 \(i\) 的距离 \(dist_i\),那么真正的 \(c_i=c_x+dist_i\)。

然后你对于每条边 \((u,v,w)\) 都检查 \(dist_v\) 是否与 \(dist_u+w\) 相等就行了。

由于我们每次连边都是从编号小的点连向编号大的点的,所以把每个连通块中编号最小的点作为基准是没问题的。

等等我们好像忽略了一个条件。

题目中要求填上一个非负整数,而我们只检验了是否可以填整数,而忽视了非负这个条件。

怎样解决呢?

对于每一行,假设有一个位置 \(j\) 填上了数 \(v\),\(j\) 所在列的连通块中编号最小的点为 \(x\)。

那么 \(r_i+c_j=v\),即 \(r_i+c_x+dist_j=v\)

于是我们得到 \(r_i+c_x=v-dist_j\)。

再假设该连通块中 \(dist_k\) 最小的点 \(z\)。

那么 \(A_{i,z}=r_i+c_z=r_i+c_x+dist_z\)。

如果 \(r_i+c_x+dist_z<0\) 就说明 \(A_{i,z}<0\),不合法。

于是这题就做完了。

/*
Contest: -
Problem: NFLSOJ 713
Author: tzc_wk
Time: 2020.10.20
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
int n,m,k;
struct data{
int x,y,z;
} a[200005];
bool cmpx(data x,data y){
return x.x<y.x;
}
bool cmpy(data x,data y){
return x.y<y.y;
}
struct edge{
int u,v,w;
} edr[200005],edc[200005];
int ecntr=0,ecntc=0;
vector<pii> gr[200005],gc[200005];
vector<data> dr[200005],dc[200005];
int disr[200005],disc[200005];
inline void adder(int u,int v,int w){
edr[++ecntr]={u,v,w};
gr[u].pb(make_pair(v,w));
}
inline void addec(int u,int v,int w){
edc[++ecntc]={u,v,w};
gc[u].pb(make_pair(v,w));
}
bool visr[200005],visc[200005];
int compr=0,compc=0;
int fromr[200005],fromc[200005];
inline void dfsr(int x){
if(visr[x]) return;
visr[x]=1;fromr[x]=compr;
for(int i=0;i<gr[x].size();i++){
int y=gr[x][i].fi,z=gr[x][i].se;
disr[y]=disr[x]+z;dfsr(y);
}
}
inline void dfsc(int x){
if(visc[x]) return;
visc[x]=1;fromc[x]=compc;
for(int i=0;i<gc[x].size();i++){
int y=gc[x][i].fi,z=gc[x][i].se;
disc[y]=disc[x]+z;dfsc(y);
}
}
int mnr[200005],mnc[200005];
int main(){
// freopen("C:\\Users\\汤\\Downloads\\problem_714\\subtask2\\zibi3.in","r",stdin);
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++){
data in;scanf("%d%d%d",&in.x,&in.y,&in.z);
dr[in.x].push_back(in);dc[in.y].push_back(in);a[i]=in;
}
for(int i=1;i<=n;i++) sort(all(dr[i]),cmpy);
for(int i=1;i<=m;i++) sort(all(dc[i]),cmpx);
for(int i=1;i<=n;i++){
if(dr[i].empty()) continue;
for(int j=1;j<dr[i].size();j++){
addec(dr[i][j-1].y,dr[i][j].y,dr[i][j].z-dr[i][j-1].z);
addec(dr[i][j].y,dr[i][j-1].y,dr[i][j-1].z-dr[i][j].z);
}
}
for(int i=1;i<=m;i++){
if((dc[i].empty())) continue;
for(int j=1;j<dc[i].size();j++){
adder(dc[i][j-1].x,dc[i][j].x,dc[i][j].z-dc[i][j-1].z);
adder(dc[i][j].x,dc[i][j-1].x,dc[i][j-1].z-dc[i][j].z);
}
}
for(int i=1;i<=n;i++) if(!visr[i]) compr++,dfsr(i);
for(int i=1;i<=m;i++) if(!visc[i]) compc++,dfsc(i);
for(int i=1;i<=ecntr;i++){
if(disr[edr[i].v]!=disr[edr[i].u]+edr[i].w)
return puts("Zikai"),0;
}
for(int i=1;i<=ecntc;i++){
if(disc[edc[i].v]!=disc[edc[i].u]+edc[i].w)
return puts("Zikai"),0;
}
for(int i=1;i<=compr;i++) mnr[i]=0x3f3f3f3f;
for(int i=1;i<=compc;i++) mnc[i]=0x3f3f3f3f;
// puts("A");
for(int i=1;i<=n;i++) mnr[fromr[i]]=min(mnr[fromr[i]],disr[i]);
for(int i=1;i<=m;i++) mnc[fromc[i]]=min(mnc[fromc[i]],disc[i]);
for(int i=1;i<=n;i++){
int mn=0x3f3f3f3f;
for(int j=0;j<dr[i].size();j++){
int x=dr[i][j].y;
mn=min(mn,dr[i][j].z-disc[x]+mnc[fromc[x]]);
// printf("%d %d %d\n",i,x,dr[i][j].z-disc[x]+mnc[fromc[x]]);
}
// printf("%d %d\n",i,mn);
if(mn<0) return puts("Zikai"),0;
}
puts("Zibi");
return 0;
}

【2020五校联考NOIP #8】自闭的更多相关文章

  1. 【2020五校联考NOIP #6】三格缩进

    题意: 给出 \(n\) 个数 \(a_1,a_2,\dots,a_n\),你要进行 \(m\) 次操作,每次操作有两种类型: \(1\ p\ x\):将 \(a_p\) 改为 \(x\). \(2\ ...

  2. 【2020五校联考NOIP #8】狗

    题面传送门 原题题号:Codeforces 883D 题意: 有 \(n\) 个位置,每个位置上要么有一条狗,要么有一根骨头,要么啥都没有. 现在你要给每个狗指定一个方向(朝左或朝右). 朝左的狗可以 ...

  3. 【2020五校联考NOIP #7】道路扩建

    题面传送门 题意: 给出一张 \(n\) 个点 \(m\) 条边的无向图 \(G\),第 \(i\) 条边连接 \(u_i,v_i\) 两个点,权值为 \(w_i\). 你可以进行以下操作一次: 选择 ...

  4. 【2020五校联考NOIP #4】今天的你依旧闪耀

    题面传送门 题意: 对于一个长度为 \(n\)(\(n\) 为偶数)的排列 \(p\),定义一次"变换"后得到的排列 \(p'\) 为: \(p'_i=\begin{cases}p ...

  5. 【2020五校联考NOIP #3】序列

    题面传送门 原题题号:Codeforces Gym 101821B 题意: 给出一个排列 \(p\),要你找出一个最长上升子序列(LIS)和一个最长下降子序列(LDS),满足它们没有公共元素.或告知无 ...

  6. 【2020五校联考NOIP #7】伟大的卫国战争

    题面传送门 题意: 数轴上有 \(n\) 个点,现在要在它们之间连 \(m\) 条边,第 \(i\) 条边连接 \(a_i,b_i\) 两个点. 现在你要钦定每条边连在数轴的上方还是下方,使得任意两条 ...

  7. 【2020五校联考NOIP #6】最佳观影

    题意: 给出一个 \(k \times k\) 的网格和 \(n\) 次操作.其中 \(k\) 为奇数. 每次操作给出一个数 \(m\).每次你要找出一个三元组 \((x,l,r)\) 使得: \(r ...

  8. 【2020五校联考NOIP #2】矩阵

    咕咕咕到现在~ 题面传送门 题意: 给出一个 \(n\times n\) 的矩阵 \(A\).要你求有多少个 \(n\times n\) 的矩阵 \(B\) 满足: 每一行都是 \(1\) 到 \(n ...

  9. 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你

    [五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...

随机推荐

  1. javascriptRemke之类的继承

    前言:es6之前在js中要实现继承,就必须要我们程序员在原型链上手动继承多对象的操作,但是结果往往存在漏洞,为解决这些问题,社区中出现了盗用构造函数.组合继承.原型式继承.寄生式继承等一系列继承方式, ...

  2. js判断移动端浏览器类型,微信浏览器、支付宝小程序、微信小程序等

    起因 现在市场上各种跨平台开发方案百家争鸣各有千秋,个人认为最成熟的还是hybird方案,简单的说就是写H5各种嵌入,当然作为前端工程师最希望的也就是公司采用hybird方案当作技术路线. 所谓的hy ...

  3. Linux中检查字符串是否为合法IP地址的shell脚本

    #!/bin/bash #判断IP地址是否为有效IP CHKECK_IP () { CHECK_STEP1=`echo $1 | awk -F"." '{print NF}'` i ...

  4. Java并发:AbstractQueuedSynchronizer(AQS)

    队列同步器 AbstractQueuedSynchronizer 是一个公共抽象类.提供一个同步器框架,用于实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等).使用一个 in ...

  5. SpringBoot整合Easyexcel操作Excel,闲暇之余,让我们学习更多

    关于封面:晚饭后回自习室的路上 Easyexcel 官方文档 Easyexcel | github 前言 最近也是在写的一个小练习中,需要用到这个.趁着这次就将写个整合的Demo给大家. 希望能够让大 ...

  6. 构建乘积数组 牛客网 剑指Offer

    构建成绩数组 牛客网 剑指Offer 题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...*A[i-1]A[i ...

  7. Python import commands ImportError: No module named 'commands'

    ImportError: No module named 'commands' 在Python3中执行shell脚本,想要获取其执行状态和标准输出.错误输出 的数据,遇到这个错误,原因是command ...

  8. hdu 5100 Chessboard (额,,,,,就叫它趣味数学题吧)

    题意: 用K*1的砖块去覆盖N*N的大矩形,问最多能覆盖多少块. 详细证明:(转载自matrix67) Matrix67: The Aha Moments 趣题:用 k × 1 的矩形覆盖 n × n ...

  9. 王爽汇编第十章,call和ret指令

    目录 王爽汇编第十章,call和ret指令 call和ret指令概述: ret和retf ret指令 retf指令 call 和 ret 的配合使用 call指令详解 call原理 call指令所有写 ...

  10. Python3 装逼神器---词云(wordcloud)

    词云 (Word Cloud)是对文本中出现频率较高的词语给予视觉化展示的图形, 是一种常见的文本挖掘的方法. 实例:     依赖包: # pip3 install wordcloud  jieba ...