P13570 连方 题解

P13570 连方 题解

P13570 连方 一道挺水的构造题,所以我们需要上手去模拟一下性质,不过实现起来细节挺多的,蒟蒻自己调了俩小时

题意简述

给定字符串长度 \(n\) 并且给定两个字符串 \(a\)\(b\),要求 \(a\)\(b\) 分别为最后构造答案的第一行与最后一行。

对于整个矩阵,要求其满足以下几点条件:

  1. 要求其中上下左右相连的符号 # ,最后总体必须构成一个矩形。
  2. 要求整个矩阵中的每个矩形,都有至少一个矩形与其对角相邻,并且每个 # 都可以向八个方向移动到另一个 # ,每两个 # 都可以相互到达。

思考过程

首先我们去手玩一下题目样例,发现了两个很容易发现的小性质。

注:因为有的浏览器会把 .# 的宽度搞的不同,所以接下来的样例模拟用 & 代替 .

性质 \(1\):对于第一行与第七行,分别在第二行与第六行把其对应的空缺填一下,就可以让第一行与第二行(第七行与第六行)中的每个矩形都相互连通,具体如下:

##&#&
&&#&#

#&#&&
&#&##//样例一中的第二个

性质 2:对于连出来的 #,只需要一个就可以让上下块连通了。

所以从以上两条性质,我们考虑怎么去让上下块进行连通。发现在第三行和第五行分别再延申出一个与二和六连通的 #,就可以在第四行只让这两个点连接,满足题目的所有要求。

而额外针对不可能的情况,我们注意到,在首尾两行中其中一行只要出现全部都是 #,那么其下一行就必须全是 # 才可以满足条件,所以除了首尾都是 #,剩下只要出现只有单个一行全都是 # 的情况,就说明是不可能构造出的情况,输出 No 即可。

总时间复杂度在抛去常数外为 \(O(\sum_{i=1}^{i<=T} n_i)\)

代码

#include <bits/stdc++.h>
using namespace std;
int t, n;
char s[10][200010];
bool solve(){
	string a, b;
	cin>>n>>a>>b;
	for(int i=1; i<=7; i++)
		for(int j=0; j<=n; j++) s[i][j]='.';//多测清空,但是在这题应该不必要
	bool ansa=0, ansb=0;//去判断两行是不是全都是#
	for(int i=0; i<n; i++){
		if(i>0&&a[i]!=a[i-1]&&!ansa)ansa=1;
		if(i>0&&b[i]!=b[i-1]&&!ansb)ansb=1;
		s[1][i]=a[i],s[7][i]=b[i];
		s[2][i]=(a[i]=='#')?'.':'#',s[6][i]=(b[i]=='#')?'.':'#';
		s[3][i]=s[4][i]=s[5][i]='.';
	}
	if(!ansa&&a==b){//如果是一样并且没有.的,就直接构造全#
		cout<<"Yes\n";
		for(int i=1; i<=7; i++){
			for(int j=0; j<n; j++)
				cout<<'#';
			cout<<'\n';
		}
		return 1;
	}
	if(!ansa||!ansb) return 0;//只要有单个一种全部都是#,就说明不对
	int u1=0, u2=0;
	for(int i=0; i<n; i++){//让3行5行延伸出一个与2,6相连的
		if(i<n-1&&s[2][i]=='#'&&s[2][i+1]=='.'&&!u1)s[3][i+1]='#',u1=i+1;
		if(i>0&&s[2][i-1]=='#'&&s[2][i]=='.'&&!u1)s[3][i]='#',u1=i;
		if(i<n-1&&s[2][i]=='.'&&s[2][i+1]=='#'&&!u1)s[3][i]='#',u1=i;
		if(i>0&&s[2][i-1]=='.'&&s[2][i]=='#'&&!u1)s[3][i-1]='#',u1=i-1;
		
		if(i<n-1&&s[6][i]=='#'&&s[6][i+1]=='.'&&!u2)s[5][i+1]='#',u2=i+1;
		if(i>0&&s[6][i-1]=='#'&&s[6][i]=='.'&&!u2)s[5][i]='#',u2=i;
		if(i<n-1&&s[6][i]=='.'&&s[6][i+1]=='#'&&!u2)s[5][i]='#',u2=i;
		if(i>0&&s[6][i-1]=='.'&&s[6][i]=='#'&&!u2)s[5][i-1]='#',u2=i-1;
	}
	if(u1>u2) swap(u1,u2);//注意大小
	for(int i=0; i<n; i++){
		s[4][i]=(u1<i&&i<u2)?'#':'.',
		s[3][i]=(s[3][i]=='#')?'#':'.',
		s[5][i]=(s[5][i]=='#')?'#':'.';
	}
	if(u2-u1<=1)s[4][u1]='#';//分别是相交与刚好错开一个的情况,特判一下
	cout<<"Yes\n";
	for(int i=1; i<=7; i++){//从1开始,不访问0 
		for(int j=0; j<n; j++){
			cout<<s[i][j];
		}
		cout<<'\n';
	}
	return 1;
}

int main(){
	cin>>t;
	while(t--){
		if(!solve())cout<<"No\n";
	}
	return 0;
}
posted @ 2026-01-27 09:46  Yuriha  阅读(25)  评论(0)    收藏  举报