1 条题解

  • 0
    @ 2026-5-28 22:10:21

    题目描述

    有一个 N×NN\times N1N10001\le N\le 1000)的矩阵,其中第 rr 行第 cc 列的方格中的整数为 r+cr+c

    33 种操作。

    1. 交换两行;
    2. 交换两列;
    3. 选择两个同时存在于表格中的值 aabb,然后同时将每一个 aa 更改为 bb,每一个 bb 更改为 aa

    Elsie 总是按类型顺序执行操作;也就是说,她首先执行任意数量(可能为零)的类型 11 操作,然后是类型 22 操作,最后是类型 33 操作。

    请求出在执行完所有类型 1122 操作后,在执行任意类型 33 操作之前,矩阵的一种可能状态。可能存在多种可能的答案,在这种情况下你应当输出字典序最小的答案。

    思路

    首先有一个性质:执行完 1122 操作后,每一行每一列的数字会变成原来的行、列的排列,就是一开始与 22 在同一行的是 332+n12+n-1,执行完 1122 操作后,与 22 在同一行的还是 332+n12+n-1

    显然,11 操作交换行,行内部的数字不会变,22 操作交换列,行内部相当于交换 22 个数的顺序,不会改变值,只会改变顺序。11 操作交换行列内部相当于交换 22 个数的数字,不会改变值,只会改变顺序,22 操作交换列,列内部的数字不会变。所以执行完 1122 操作后,每一行每一列的数字只会变顺序,一开始与 22 在同一行同一列的数字执行完 1122 操作后还是与 22 在同一行同一列。

    然后,只有一开始的第 11 行有 22,一开始的最后 11 行有 n×2n\times 222n×2n\times 2 都只出现了一次,很好确定位置,与 22 在同一行的是 22n+1n+1,与 n×2n\times 2 在同一行的是 n+1n+1n×2n\times 2,通过出现次数刚好可以确定所有的数,因为出现次数是 11 的有 22 个数,我们不知道哪个是 11 哪个是 n×2n\times 2,所以答案有 22 种,我们分两种情况算完后比较字典序即可。

    代码

    #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
    上传者