题解:P11672 [USACO25JAN] Table Recovery S

P11672 [USACO25JAN] Table Recovery S 题解

题目描述

对于一个 \(N\times N\)\(1\le N\le 1000\))的加法表,其中对于所有 \(1\le r,c\le N\),第 \(r\) 行第 \(c\) 列的方格中的整数为 \(r+c\)

对其进行如下操作:

  1. 重新排列行;
  2. 重新排列列;

使其与输入表格形式相同。(即 \(\forall a \in \text{加法表}\),所对应在输入表格第 \(r\) 行第 \(c\) 列的元素都为 \(b\)

寻找字典序最小的合法表格。

按字典序比较两个表格时,比较它们在自然顺序(行间从上到下,行内从左到右)下读取时第一个不同的项。

题目分析

只出现一次的只有 \(2\)\(2n\),出现 \(2\) 时必定是 \(1+1\),所在一行必定是 \(1+(count_{a_{r c}}-1)\),所在一列必定是 \((count_{a_{r c}}-1)+1\)。此时分类讨论 \(2\),比较两个表格字典序,输出。

复杂度

编程语言 C++14 (GCC 9) O2

代码长度 998B

用时 452ms

内存 23.62MB

CODE

#include<bits/stdc++.h>
#define int long long
const int N=1e3+5;
int n;
int a[N][N],cnt[N<<1];
int R[2][N],C[2][N],ans[2][N][N];
bool calc(){//比较两个表格字典序 
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(ans[0][i][j]!=ans[1][i][j])
				return ans[0][i][j]>ans[1][i][j];
	return 0;
}
signed main(){
	std::ios::sync_with_stdio(0);
	std::cin.tie(0),std::cout.tie(0);
	std::cin>>n;
	if(n==1){//特判 
		std::cout<<2;
		return 0;
	}
	for(int i=1;i<=n;i++)//读入,计数 
		for(int j=1;j<=n;j++){
			std::cin>>a[i][j];
			cnt[a[i][j]]++;
		}
	for(int i=1,k=0;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(cnt[a[i][j]]==1){//分类构造行列 
				for(int r=1;r<=n;r++)	R[k][r]=cnt[a[r][j]];
				for(int c=1;c<=n;c++)	C[k][c]=cnt[a[i][c]];
				if(++k==2)	break;
			}
	for(int num=0;num<=1;num++)//构造两个表格 
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				ans[num][i][j]=R[num][i]+C[num][j];
	int k=calc();
	for(int i=1;i<=n;i++){//输出 
		for(int j=1;j<=n;j++)
			std::cout<<ans[k][i][j]<<' ';
		std::cout<<'\n';
	}
	return 0;
}

完结撒花

posted @ 2026-01-29 21:49  concert_b  阅读(0)  评论(0)    收藏  举报