纯思维,“模拟”是因为不知道写什么标签。
给定 \(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有点糊):
下面是 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;
}