思维性很强的题目,想不到就是想不到。

纯思维,“模拟”是因为不知道写什么标签。

给定 \(r\)\(c\) 列字符矩阵,每个元素为 . 或者 R。给定正整数 \(k\),现将要字符矩阵划分为四连通的 \(k\) 块,并定义每个连通块的权值为其中 R 的个数。

如何让最大权值减最小权值最小?记矩阵中 R 的个数为 \(cnt\),则令 \(cnt\mod k\) 块中 R 的个数为 \(\large\lceil \frac{cnt}{k}\rceil\),剩下的块为 \(\large\lfloor \frac{cnt}{k}\rfloor\) 即可。

感觉这件事情很容易办到。但是直到模拟赛结束我也没。因为要使得这些块四联通,所以从每个 R 出发是不行的,正确的方法是一笔走完整个矩阵,不管是蛇形、螺旋型还是随机型!笔者写法如下图所示,先向左走,走到头向下换行,再向右走(mspaint有点糊):

CF1254A Feeding Chicken(模拟)_基础算法

下面是 AC 代码局部,首先是主函数部分(输入输出略):

int per=cnt/k,more=cnt%k,less=k-more,col=0;
//more块包含per+1个R,less块包含per个R
node las=(node){1,1,1};
while(more--)	las=color(las,per+1,col++);//从las开始,找per+1个R,涂上col颜色
while(less--)	las=color(las,per,col++);
if(las.x/*color函数里,如果走完返回0*/) color(las,1,--col);//保证..R(......)段被涂色

涂色函数,注意换行细节。

struct node{int x,y,d;};
char a[105][105],ans[105][105];
//向右为1,向左为-1,方便运算
inline node color(node now,int need,int col){
	do{
		ans[now.x][now.y]=get(col);//col是数字,get()找到对应的颜色
		if(now.x==r&&(r&1?now.y==c:now.y==1)) return (node){0,0,0};//呼应上文
		if(a[now.x][now.y]=='R'){
			--need;
			if(!need){
				if(now.y==c&&now.d==1) return (node){now.x+1,c,-1};
				else if(now.y==1&&now.d==-1) return (node){now.x+1,1,1};//跳到下一行
				else return (node){now.x,now.y+now.d,now.d};
			}
		}	
		if(now.y+now.d>c||now.y+now.d<1) ++now.x,now.d=-now.d;
		else now.y+=now.d;
	}while(true);
}

通过 ASCII 码实现涂色,避免长达 62 位的打表。

inline char get(int col){
	if(col<=9) return '0'+col;
	else if(col<=35) return 'a'+col-10;
	else return 'A'+col-36;
}

THE END