题解: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\)。
对其进行如下操作:
- 重新排列行;
- 重新排列列;
使其与输入表格形式相同。(即 \(\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;
}

浙公网安备 33010602011771号