Codeforces 1383D - Rearrange(构造)

Codeforces 题面传送门 & 洛谷题面传送门

一道不算困难的构造,花了一节英语课把它搞出来了,题解简单写写吧(

考虑从大往小加数,显然第三个条件可以被翻译为,每次加入一个元素,如果它所在的行/列存在元素,那么它必须为这一行/列所在的元素相邻,因此我们考虑这样构造,当我们加入一个数 \(v\) 时,分以下几种情况考虑:

  • 如果 \(v\) 在原矩阵中既是行的最大值,也是列的最大值,那我们新开一行一列并将这个元素塞进去。即我们动态维护一个 \(R,C\) 表示目前有 \(R\) 行 \(C\) 列有元素,那么遇到这样的 \(v\),我们令 \(R,C\) 都加一然后令 \(b_{R,C}=v\) 即可。
  • 如果 \(v\)​​ 在原矩阵中只是行的最大值不是列的最大值,那么我们只令 \(R\)​​ 加 \(1\)​​ 而不用令 \(C\)​​ 加 \(1\)​​,然后还是令 \(b_{R,C}=v\)。
  • 如果 \(v\)​​ 在原矩阵中只是列的最大值不是行的最大值,与上面的情况不同之处在于,这次我们要令 \(C\) 加 \(1\) instead of \(R\)。
  • 如果 \(v\) 在原矩阵中既不是行的最大值也不是列的最大值,那么我们就找到一个位置 \((x,y)\) 满足 \((x,y)\) 上未填上数,并且 \((x,y)\) 恰好与两个已经填上格子的位置相邻,并令 \(b_{x,y}=v\)。可以证明我们总能找到这样的位置,因为在值最大的 \(RC+1\) 个格子中必然要么有超过 \(R\) 个行最大值,要么有超过 \(C\) 个列最大值,因此不会出现没地方填的情况。而显然如果前 \(R\) 行 \(C\) 列没有填满,由于我们构造的特殊性,我们总能找到一个空格子满足其与 \(2\) 个填上值的位置相邻,因此我们的构造总是合法的。这一部分可以通过维护一个队列,每次新填上一个值就遍历一遍与其相邻的格子,检验其是否与 \(2\) 个填上值的位置相邻来实现。

时间复杂度 \(\mathcal O(nm)\)

const int MAXN=250;
const int dx[]={1,0,-1,0};
const int dy[]={0,1,0,-1};
int n,m,a[MAXN+5][MAXN+5],vis1[MAXN*MAXN+5],vis2[MAXN*MAXN+5];
int X=0,Y=0,b[MAXN+5][MAXN+5];queue<pii> q;
bool check(int x,int y){
	if(x<1||x>n||y<1||y>m) return 0;
	if(b[x][y]) return 0;
	int cnt=0;
	for(int i=0;i<4;i++) cnt+=(b[x+dx[i]][y+dy[i]]>0);
	return cnt==2;
}
void relax(int x,int y){
	for(int i=0;i<4;i++) if(check(x+dx[i],y+dy[i])) q.push(mp(x+dx[i],y+dy[i]));
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
	for(int i=1;i<=n;i++){
		int mx=0;
		for(int j=1;j<=m;j++) chkmax(mx,a[i][j]);
		vis1[mx]=1;
	}
	for(int i=1;i<=m;i++){
		int mx=0;
		for(int j=1;j<=n;j++) chkmax(mx,a[j][i]);
		vis2[mx]=1;
	}
	for(int i=n*m;i;i--){
		if(vis1[i]&&vis2[i]) b[++X][++Y]=i,relax(X,Y);
		else if(vis1[i]) b[++X][Y]=i,relax(X,Y);
		else if(vis2[i]) b[X][++Y]=i,relax(X,Y);
		else{
			while(1){
				pii p=q.front();q.pop();
				if(!b[p.fi][p.se]){
					b[p.fi][p.se]=i;
					relax(p.fi,p.se);
					break;
				}
			}
		}
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
		printf("%d%c",b[i][j]," \n"[j==m]);
	return 0;
}
上一篇:UVA278 UVALive5586 Chess【水题】


下一篇:20200226补题