【2020五校联考NOIP #8】自闭
题目传送门
题意:
有一个 \(n \times m\) 的矩阵,里面已经填好了 \(k\) 个非负整数。
问是否能在其它 \(n \times m-k\) 个格子里各填上一个非负整数,使得得到的矩阵满足以下条件:
- 在任意一个 \(2 \times 2\) 的子矩阵中,左上角的数 \(+\) 右下角的数 \(=\) 右上角的数 \(+\) 左下角的数。
如果可以输出 Zibi 否则输出 Zikai。
\(n,m,k \in [1,10^5]\)
考虑探究这个矩阵有什么性质。假设有一个 \(3 \times 3\) 的子矩阵:
\]
根据上面的条件我们有:
\]
由第一个和第三个式子可以得到 \(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\),都有
\]
根据这个性质,考虑固定住第一行和第一列,根据上面的性质填好剩下 \((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】自闭的更多相关文章
- 【2020五校联考NOIP #6】三格缩进
题意: 给出 \(n\) 个数 \(a_1,a_2,\dots,a_n\),你要进行 \(m\) 次操作,每次操作有两种类型: \(1\ p\ x\):将 \(a_p\) 改为 \(x\). \(2\ ...
- 【2020五校联考NOIP #8】狗
题面传送门 原题题号:Codeforces 883D 题意: 有 \(n\) 个位置,每个位置上要么有一条狗,要么有一根骨头,要么啥都没有. 现在你要给每个狗指定一个方向(朝左或朝右). 朝左的狗可以 ...
- 【2020五校联考NOIP #7】道路扩建
题面传送门 题意: 给出一张 \(n\) 个点 \(m\) 条边的无向图 \(G\),第 \(i\) 条边连接 \(u_i,v_i\) 两个点,权值为 \(w_i\). 你可以进行以下操作一次: 选择 ...
- 【2020五校联考NOIP #4】今天的你依旧闪耀
题面传送门 题意: 对于一个长度为 \(n\)(\(n\) 为偶数)的排列 \(p\),定义一次"变换"后得到的排列 \(p'\) 为: \(p'_i=\begin{cases}p ...
- 【2020五校联考NOIP #3】序列
题面传送门 原题题号:Codeforces Gym 101821B 题意: 给出一个排列 \(p\),要你找出一个最长上升子序列(LIS)和一个最长下降子序列(LDS),满足它们没有公共元素.或告知无 ...
- 【2020五校联考NOIP #7】伟大的卫国战争
题面传送门 题意: 数轴上有 \(n\) 个点,现在要在它们之间连 \(m\) 条边,第 \(i\) 条边连接 \(a_i,b_i\) 两个点. 现在你要钦定每条边连在数轴的上方还是下方,使得任意两条 ...
- 【2020五校联考NOIP #6】最佳观影
题意: 给出一个 \(k \times k\) 的网格和 \(n\) 次操作.其中 \(k\) 为奇数. 每次操作给出一个数 \(m\).每次你要找出一个三元组 \((x,l,r)\) 使得: \(r ...
- 【2020五校联考NOIP #2】矩阵
咕咕咕到现在~ 题面传送门 题意: 给出一个 \(n\times n\) 的矩阵 \(A\).要你求有多少个 \(n\times n\) 的矩阵 \(B\) 满足: 每一行都是 \(1\) 到 \(n ...
- 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你
[五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...
随机推荐
- Clusternet v0.5.0 重磅发布: 全面解决多集群应用分发的差异化配置难题
作者 徐迪,腾讯云容器技术专家. 汝英哲,腾讯云高级产品经理. 摘要 在做多集群应用分发的时候,经常会遇到以下的差异化问题,比如: 在分发的资源上全部打上统一的标签,比如 apps.my.compan ...
- 第五课第四周笔记1:Transformer Network Intuition 变压器网络直觉
目录 Transformer Network Intuition 变压器网络直觉 Transformer Network Intuition 变压器网络直觉 深度学习中最令人兴奋的发展之一是 Tran ...
- 面试题系列:new String("abc")创建了几个对象
new String("abc")创建了几个对象 面试官考察点猜想 这种问题,考察你对JVM的理解程度.涉及到常量池.对象内存分配等问题. 涉及背景知识详解 在分析这个问题之前,我 ...
- Spring Security 多过滤链的使用
Spring Security 多过滤链的使用 一.背景 二.需求 1.给客户端使用的api 2.给网站使用的api 三.实现方案 方案一: 方案二 四.实现 1.app 端 Spring Secur ...
- logstash处理多行日志-处理java堆栈日志
logstash处理多行日志-处理java堆栈日志 一.背景 二.需求 三.实现思路 1.分析日志 2.实现,编写pipeline文件 四.注意事项 五.参考文档 一.背景 在我们的java程序中,经 ...
- 零基础学习Linux心得总结
很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...
- 六个好习惯让你的PCB设计更优(转)
PCB layout工程师每天对着板子成千上万条走线,各种各样的封装,重复着拉线的工作,也许很多人会觉得是很枯燥无聊的工作内容.看似软件操作搬运工,其实设计人员在过程中要在各种设计规则之间做取舍,兼顾 ...
- [转]DDR相关的一些基础知识
ODT ( On-DieTermination ,片内终结)ODT 也是 DDR2 相对于 DDR1 的关键技术突破,所谓的终结(端接),就是让信号被电路的终端吸 收掉,而不会在电路上形成反射, 造成 ...
- 认识Linux系统中的inode,硬链接和软链接
在学习和创建软链接遇到了一点问题,总结一下: 在当前文件夹下面建立了两个临时文件夹tempdir1和tempdir2,然后在tempdir2里面创建了一个hello文件,然后用指令ln -s temp ...
- 检查是否是BST 牛客网 程序员面试金典 C++ java Python
检查是否是BST 牛客网 程序员面试金典 C++ java Python 题目描述 请实现一个函数,检查一棵二叉树是否为二叉查找树. 给定树的根结点指针TreeNode* root,请返回一个boo ...