P13570 连方 题解
P13570 连方 题解
P13570 连方 一道挺水的构造题,所以我们需要上手去模拟一下性质,不过实现起来细节挺多的,蒟蒻自己调了俩小时。
题意简述
给定字符串长度 \(n\) 并且给定两个字符串 \(a\),\(b\),要求 \(a\) 和 \(b\) 分别为最后构造答案的第一行与最后一行。
对于整个矩阵,要求其满足以下几点条件:
- 要求其中上下左右相连的符号
#,最后总体必须构成一个矩形。- 要求整个矩阵中的每个矩形,都有至少一个矩形与其对角相邻,并且每个
#都可以向八个方向移动到另一个#,每两个#都可以相互到达。
思考过程
首先我们去手玩一下题目样例,发现了两个很容易发现的小性质。
注:因为有的浏览器会把 . 和 # 的宽度搞的不同,所以接下来的样例模拟用 & 代替 .。
性质 \(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;
}

浙公网安备 33010602011771号