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;
}

浙公网安备 33010602011771号