题目传送门

题意:

有一个 \(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. 初识HTML01

    什么是页面? 页面是基于浏览器的应用程序 页面是数据展示的载体,由浏览器和服务器共同执行产物. 浏览器的功能 向服务器发送用户请求指令 接收并解析数据展示给用户 服务器的功能 存储页面资源 处理并响应 ...

  2. Golang通脉之接口

    接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类型. interface是 ...

  3. 安装多个版本的 JDK

    安装多个版本的 JDK 刚刚开始学 Java 的时候安装了 JDK9 版本,后续发现还是 JDK8 使用的多些,而又不想删除原先版本 因此安装两个版本的 JDK 在需要是切换一下即可 1. 安装第一个 ...

  4. dwr简单应用及一个反向ajax消息推送

    由于项目中最近需要用到dwr实现一些功能,因此在网上和dwr官网上找了一些资料进行学习.在此记录一下.(此处实现简单的dwr应用和dwr消息反向推送) 一.引入dwr的包 <dependency ...

  5. Python课程笔记(十)

    不陌生,之前学习一个开源SpringBoot项目,Mysql5.5更换到5.7搞得头疼. 数据库连接的坑之前写的IDEA系列连接会遇到的问题.课程代码 今天上课就主要学习了python如何连接mysq ...

  6. Vue:Vue的介绍以及组件剖析

    介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...

  7. Python AttributeError: module 'string' has no attribute 'atoi'

    python2 中可以用string.atoi 在python3中会报错 替换的方案是 string.atoi(your_str) 替换为 int(your_str) 这个代码python2和pyth ...

  8. 第K个数 牛客网 程序员面试金典 C++ Python

    第K个数 牛客网 程序员面试金典 C++ Python 题目描述 有一些数的素因子只有3.5.7,请设计一个算法,找出其中的第k个数. 给定一个数int k,请返回第k个数.保证k小于等于100. 测 ...

  9. path-sum leetcode C++

    Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...

  10. Markdown使用方式

    区块 区块引用在段落开头使用>,后面紧跟一个空格符号 > 区块引用 > XXX > XXX 高级技巧 HTML元素 居中  <center>XXX</cent ...