专栏文章

题解:CF2121C Those Who Are With Us

CF2121C题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miozj869
此快照首次捕获于
2025/12/03 03:42
3 个月前
此快照最后确认于
2025/12/03 03:42
3 个月前
查看原文
[Problem Discription]\color{blue}{\texttt{[Problem Discription]}}
给定一个 n×mn \times m 的表格 ai,ja_{i,j},你可以恰好进行一次如下操作:
  1. 选择一个格点 (r,c)(r,c)
  2. 对于所有满足 i=ri=r 或者 j=cj=c 的格点 (i,j)(i,j),使 ai,jai,j1a_{i,j} \leftarrow a_{i,j}-1
求操作后所有格点最大值最小可能为多少。
多组数据,满足 1n×m1×1051 \leq n \times m \leq 1 \times 10^{5},且所有数据的 n×mn \times m 的总和不超过 2×1052 \times 10^{5}
[Analysis]\color{blue}{\texttt{[Analysis]}}
记原来矩阵的最大值为 tt,显然由于只能进行一次操作,且一次操作最多让一个格点的值减小 11,所以最终答案要么是 tt,要么是 (t1)(t-1)
思考哪些情况会让答案为 (t1)(t-1)
显然,当所有取得最大值的格点要么分布在第 rr 行要么分布在第 cc 列时,我们可以通过一次操作 (r,c)(r,c) 把所有最大值都干掉;否则答案为 tt 不变。
统计每一行每一列有多少个最大值,分别记为 cntri,cntcj\text{cntr}_{i},\text{cntc}_{j},显然第 ii 行和第 jj 列的最大值的个数即为:
f(i,j)=cntri+cntcj[ai,j=max1in,1jm{ai,j}]f(i,j)=\text{cntr}_{i}+\text{cntc}_{j}- \left [a_{i,j}=\max\limits_{1 \leq i \leq n, 1 \leq j \leq m} \{a_{i,j} \}\right ]
显然预先统计出最大值的个数 cnt\text{cnt},如果某个格点 (i,j)(i,j) 满足 f(i,j)=cntf(i,j)=\text{cnt},那么这个 (i,j)(i,j) 就是我们需要的格点。
Code\color{blue}{\text{Code}}
CPP
const int N=1e5+100;

int OneZDoubleY(){
	int n=read(),m=read();
	vector<int> a[n+2];
	for(int i=1;i<=n;i++){
		a[i].push_back(0);
		for(int j=1;j<=m;j++)
			a[i].push_back(read());
	}
	
	int maxn=a[1][1];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			ckmax(maxn,a[i][j]);
	
	int cnt=0;
	vector<int> cntr(n+1),cntc(m+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if (a[i][j]==maxn){
				++cntr[i];
				++cntc[j];
				++cnt;
			}
	
	bool flag=false;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			int t=cntr[i]+cntc[j];
			if (a[i][j]==maxn) t--;
			
			if (t==cnt){
				flag=true;
				break;
			}
		}
	
	return printf("%d\n",flag?maxn-1:maxn);
}
//大家可以挑战一下不用 vector,用 malloc 来处理

int main(){
	int T=read();
	while (T--) OneZDoubleY();
	
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...