Codeforces 1335F Robots on a Grid

Description

给一个 $n \times m$ 的网格图,每个位置有颜色和方向。颜色为黑 / 白,方向表示这个位置的机器人下一步会往上下左右哪个方向移动一格,问你最多可以放多少个机器人,使得这些机器人行走时永远不会相遇。最大化个数的基础上,最大化黑色格子的机器人个数。

Solution

一直无限走下去实在玄学,看看能不能转化一下。

因为格子有限,所以 无限 $=$ 循环

换一种方法,我们可以先把每个位置都摆上机器人,一直走起来,删去会重复的。

显然,每个机器人都是先经过一些奔波,然后在一个环里面一直走下去。

比如我们现在随便弄来两个机器人,怎么知道它们会不会重复呢?

首先,假设两个机器人各自奔波时没相遇,也就是到了自己的目标环中,那么它们就永远不会相遇了。这很好理解,如果它们不在一个环中,那显然不可能碰到;如果在一个环中(当然前提是不在一个位置),那么他们之间的距离就永远不会变了,也不会相遇。

所以,两个机器人相遇的充要条件就是在奔波的路途上相遇,而且之后,该相遇的就一直在一起走了,不该相遇的就永远碰不到了。

所以,每一条道路的长度肯定不会超过图的总大小(即 $nm$),所以我们只要让每一个位置的机器人都走 $nm$ 步,然后统计位置就行了。

至于具体怎么统计,可以弄一个 $have_{0/1, \text{pos}}$ 表示最终 $\text{pos}$ 这个位置有没有黑 / 白色的机器人,然后令 $tot$ 表示总数,$black$ 表示总黑色机器人数,那么就是:

$$\begin{array}{l|l}1 & \textbf{for } i \gets 1 \textbf{ to } nm \textbf{ do} \\ 2 & \qquad \textbf{if } have_{0, i} = \text{true} \textbf{ then } tot \gets tot + 1, black \gets black + 1 \\ 3 & \qquad \textbf{else if } have_{1, i} = \text{true} \textbf{ then } tot \gets tot + 1 \\ 4 & \qquad \textbf{end if} \\ 5 & \textbf{end for}\end{array}$$

代码仅供参考。

#include <bits/stdc++.h>
using namespace std;
const int NM = 1e6 + 5, LGSZ = 21;
int n, m, nxt[LGSZ][NM];
char dir[NM], col[NM], buf[NM];
bool have[2][NM];
int main() 
{
	int t;
	scanf("%d", &t);
	while(t--) 
	{
		scanf("%d %d", &n, &m);
		for(int i = 1; i <= n * m; i++)
			have[0][i] = have[1][i] = false;
		for(int i = 1; i <= n; i++) 
		{
			scanf("%s", buf + 1);
			for(int j = 1; j <= m; j++)
				col[(i - 1) * m + j] = buf[j];
		}
		for(int i = 1; i <= n; i++) 
		{
			scanf("%s", buf + 1);
			for(int j = 1; j <= m; j++)
				dir[(i - 1) * m + j] = buf[j];
		}
		for(int i = 1; i <= n * m; i++)
			switch(dir[i])
			{
				case 'U': nxt[0][i] = i - m; break;
				case 'D': nxt[0][i] = i + m; break;
				case 'L': nxt[0][i] = i - 1; break;
				case 'R': nxt[0][i] = i + 1; break;
			}
		for(int i = 1; i < LGSZ; i++)
			for(int j = 1; j <= n * m; j++)
				nxt[i][j] = nxt[i - 1][nxt[i - 1][j]];
		for(int i = 1; i <= n * m; i++)
		{
			int pos = i;
			for(int j = LGSZ - 1; ~j; j--)
				if(n * m >> j & 1) pos = nxt[j][pos];
			have[col[i] ^ 48][pos] = true;
		}
		int black = 0, tot = 0;
		for(int i = 1; i <= n * m; i++)
		{
			if(have[0][i]) tot++, black++;
			else if(have[1][i]) tot++;
		}
		printf("%d %d\n", tot, black);
	}
	return 0;
}
posted @ 2020-04-19 00:34  syksykCCC  阅读(277)  评论(1编辑  收藏  举报