1 条题解
-
0
题目描述
有一个 ()的矩阵,其中第 行第 列的方格中的整数为 。
有 种操作。
- 交换两行;
- 交换两列;
- 选择两个同时存在于表格中的值 和 ,然后同时将每一个 更改为 ,每一个 更改为 。
Elsie 总是按类型顺序执行操作;也就是说,她首先执行任意数量(可能为零)的类型 操作,然后是类型 操作,最后是类型 操作。
请求出在执行完所有类型 和 操作后,在执行任意类型 操作之前,矩阵的一种可能状态。可能存在多种可能的答案,在这种情况下你应当输出字典序最小的答案。
思路
首先有一个性质:执行完 、 操作后,每一行每一列的数字会变成原来的行、列的排列,就是一开始与 在同一行的是 到 ,执行完 、 操作后,与 在同一行的还是 到 。
显然, 操作交换行,行内部的数字不会变, 操作交换列,行内部相当于交换 个数的顺序,不会改变值,只会改变顺序。 操作交换行列内部相当于交换 个数的数字,不会改变值,只会改变顺序, 操作交换列,列内部的数字不会变。所以执行完 、 操作后,每一行每一列的数字只会变顺序,一开始与 在同一行同一列的数字执行完 、 操作后还是与 在同一行同一列。
然后,只有一开始的第 行有 ,一开始的最后 行有 , 和 都只出现了一次,很好确定位置,与 在同一行的是 到 ,与 在同一行的是 到 ,通过出现次数刚好可以确定所有的数,因为出现次数是 的有 个数,我们不知道哪个是 哪个是 ,所以答案有 种,我们分两种情况算完后比较字典序即可。
代码
#include<iostream> #include<cstring> using namespace std; int n,a[1005][1005],cnt[2005],fa[2005],s1,s2,ans1[1005][1005],ans2[1005][1005]; int check() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(ans1[i][j]<ans2[i][j]) return true; if(ans1[i][j]>ans2[i][j]) return false; } } return 924; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&a[i][j]); cnt[a[i][j]]++; } } for(int i=1;i<=n;i++) { bool flag=false; for(int j=1;j<=n;j++) { if(cnt[a[i][j]]==1) { if(!s1) s1=i; else { s2=i; flag=true; break; } } } if(flag) break; } for(int i=1;i<=n;i++) { fa[a[s1][i]]=cnt[a[s1][i]]+1; fa[a[s2][i]]=n*2-cnt[a[s2][i]]+1; } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) ans1[i][j]=fa[a[i][j]]; } for(int i=1;i<=n;i++) { fa[a[s1][i]]=n*2-cnt[a[s1][i]]+1; fa[a[s2][i]]=cnt[a[s2][i]]+1; } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) ans2[i][j]=fa[a[i][j]]; } if(check()) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%d ",ans1[i][j]); printf("\n"); } } else { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%d ",ans2[i][j]); printf("\n"); } } }
- 1
信息
- ID
- 6920
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 99
- 已通过
- 18
- 上传者