[ACNOI2022]提交答案题

89 篇文章 0 订阅

题目

题目描述
这是一道 提交答案题

有一个 n × n n\times n n×n 网格图。每个格子可以染成红色、蓝色,或者不染色。

有若干提示,形如 “从第 i i i 行(或列)的上方或下方(或左方、右方)开始数,第一个染了色的格子是第 x x x 个,颜色为 c c c ”,或者是 “该行(或列)没有染色格子”。

保证提示之间互不冲突。请你找出一个方案,使得同色四连通块的个数不超过 q q q

数据范围与提示
n ⩽ 1000 n\leqslant 1000 n1000

思路

不要害怕提交答案,因为原理其实很简单。

将必须不染色的格子和外界称为 “墙”。那么染了色的格子总在墙的边缘。所以,对于一个由墙和已经染了色的格子围出的区域,类似于圆上的异色点连边。

那么显然,“圆” 上相邻的同色点,可以立即连边。之后 “圆” 就成了红蓝相间。可以发现,此时将某种颜色全部相连最优。换句话说,环上有 n n n 个点时,最多连 ⌈ n 2 ⌉ − 1 \lceil{n\over 2}\rceil-1 2n1 条边。

证明可以采用归纳法。随意连一条边,则两边变为独立子问题,大小分别为 a , b a,b a,b 时贡献为 ⌈ a 2 ⌉ + ⌈ b 2 ⌉ − 1 \lceil{a\over 2}\rceil+\lceil{b\over 2}\rceil-1 2a+2b1,而 a + b = n − 1 a+b=n-1 a+b=n1,所以该值一定不超过 ⌈ n 2 ⌉ − 1 \lceil{n\over 2}\rceil-1 2n1

所以我们只需要做到:沿着墙边行走,将同色相连;找到每个空洞,涂成同一种颜色。

然而,实际情况并不是一个 “圆” 那么简单,上面的模型有些理想化。所以,有一个点过不了,需要手玩;另外的点,有可能只能逆时针走(而不能顺时针沿着墙走)。

连这个都要调试这么久,我泪目了

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
	int a = 0, c = getchar(), f = 1;
	for(; !isdigit(c); c=getchar())
		if(c == '-') f = -f;
	for(; isdigit(c); c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MAXN = 1005;
char str[10], maze[MAXN][MAXN];
void input(int n){
	rep(i,1,n){
		scanf("%s",str);
		if(*str == '-') continue;
		if(*str == '0'){
			rep(j,1,n) maze[j][i] = '-';
			continue;
		}
		int id; sscanf(str,"%d",&id);
		rep(j,1,id-1) maze[j][i] = '-';
		maze[id][i] = str[strlen(str)-1];
	}
	rep(i,1,n){
		scanf("%s",str);
		if(*str != '-'){
			if(*str == '0')
				rep(j,1,n) maze[i][j] = '-';
			else{
				int id; sscanf(str,"%d",&id);
				rep(j,1,id-1) maze[i][j] = '-';
				maze[i][id] = str[strlen(str)-1];
			}
		}
		scanf("%s",str);
		if(*str != '-'){
			if(*str == '0')
				rep(j,1,n) maze[i][j] = '-';
			else{
				int id; sscanf(str,"%d",&id);
				drep(j,n,n+2-id) maze[i][j] = '-';
				maze[i][n+1-id] = str[strlen(str)-1];
			}
		}
	}
	rep(i,1,n){
		scanf("%s",str);
		if(*str == '-') continue;
		if(*str == '0'){
			rep(j,1,n) maze[j][i] = '-';
			continue;
		}
		int id; sscanf(str,"%d",&id);
		drep(j,n,n+2-id) maze[j][i] = '-';
		maze[n+1-id][i] = str[strlen(str)-1];
	}
	rep(i,1,n) rep(j,1,n)
		if(!maze[i][j]) maze[i][j] = ' ';
}

const int dir[][2] = {1,0,0,1,-1,0,0,-1}; // URDL
struct Node{
	int x, y, col;
	Node() = default;
	Node(int _x,int _y,int _c):x(_x),y(_y),col(_c){}
};
Node walk_on_wall(int x,int y,int d,bool _first=true){
	int tx = x+dir[(d+1)&3][0], ty = y+dir[(d+1)&3][1];
	if(maze[tx][ty] == ' ') // turn right
		return walk_on_wall(tx,ty,(d+1)&3,false);
	if(maze[tx][ty] != '-' && !_first)
		return Node(x,y,maze[tx][ty]);
	if(maze[x+dir[d][0]][y+dir[d][1]] != ' ')
		return walk_on_wall(x,y,(d-1)&3,false);
	return walk_on_wall(x+dir[d][0],y+dir[d][1],d,false);
}
char maze_bank[MAXN][MAXN];
void paint_on_wall(int x,int y,int d,int col,int ex,int ey){
	maze_bank[x][y] = col; // to link between corner
	if(x == ex && y == ey) return ; // even the destination
	int tx = x+dir[(d+1)&3][0], ty = y+dir[(d+1)&3][1];
	if(maze[tx][ty] == ' ') // turn right
		return paint_on_wall(tx,ty,(d+1)&3,col,ex,ey);
	if(maze[x+dir[d][0]][y+dir[d][1]] != ' ') // turn left
		return paint_on_wall(x,y,(d-1)&3,col,ex,ey);
	return paint_on_wall(x+dir[d][0],y+dir[d][1],d,col,ex,ey);
}

int cntcol[256]; bool vis[MAXN][MAXN];
void tag_component(int x,int y){
	if(vis[x][y]) return ; else vis[x][y] = true;
	rep(d,0,3) if(maze[x+dir[d][0]][y+dir[d][1]] == maze[x][y])
		tag_component(x+dir[d][0],y+dir[d][1]);
}
void scan(int x,int y){
	if(maze[x][y] == '-' || vis[x][y]) return ;
	if(maze[x][y] != ' '){ // colored
		tag_component(x,y);
		++ cntcol[int(maze[x][y])];
	}
	else vis[x][y] = true;
	rep(d,0,3) scan(x+dir[d][0],y+dir[d][1]);
}
void paint_all(int x,int y,int col){
	if(maze[x][y] != ' ') return ; else maze[x][y] = col;
	rep(d,0,3) paint_all(x+dir[d][0],y+dir[d][1],col);
}

void paint_maze(int n,char c){
	rep(i,1,n){
		rep(j,1,n)
			if(maze[i][j] == ' ') putchar(c);
			else putchar(maze[i][j]);
		putchar('\n');
	}
}

int main(){
	int n = readint(); readint(); input(n);
	rep(i,0,n+1) maze[0][i] = maze[i][0]
		= maze[n+1][i] = maze[i][n+1] = '-';

	return paint_maze(n,' '), 0;
	
	rep(i,1,n) rep(j,1,n) if(maze[i][j] == ' ') rep(d,0,3){
		char bro = maze[i+dir[d][0]][j+dir[d][1]];
		if(bro != 'M' && bro != 'B') continue;
		if(maze[i+dir[(d-1)&3][0]][j+dir[(d-1)&3][1]] == ' '
		&& maze[i+dir[d][0]+dir[(d-1)&3][0]]\
		[j+dir[d][1]+dir[(d-1)&3][1]] == ' ')
			continue; // can rotate 90 degree
		Node nxt = walk_on_wall(i,j,(d-1)&3);
		if(bro == nxt.col){ // not for maze[i][j] !
			if(nxt.x == i+dir[(d-1)&3][0]
			&& nxt.y == j+dir[(d-1)&3][1])
				continue; // already adjacent cells
			rep(k,0,n+1) memcpy(maze_bank[k],maze[k],n+2);
			paint_on_wall(i,j,(d-1)&3,bro,nxt.x,nxt.y);
			rep(k,0,n+1) memcpy(maze[k],maze_bank[k],n+2);
		}
	}

	rep(i,1,n) rep(j,1,n) if(maze[i][j] == ' '){
		rep(k,1,n) memset(vis[k]+1,false,n);
		cntcol['M'] = cntcol['B'] = 0;
		scan(i,j); int best = 'B';
		if(cntcol['M'] > cntcol['B']) best = 'M';
		if(!cntcol[best]) continue; // empty
		paint_all(i,j,best);
	}

	paint_maze(n,'-');
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值