CF-Round #634-div3-F题
F. Robots on a Grid
这道题图论,关于基环内向树的,用到了倍增。
题目大意:给你一个矩阵,矩阵的每个格子都有颜色,‘0’代表黑色,‘1’代表白色。每个格子上都标有走的方向。‘L’, ‘R’, ‘D’, ‘U’;
现在可以在这些格子上放一些机器人,这些机器人会按照格子所给的方向走,要求在任何时候都不允许有两个机器人在一个格子上的情况。(也就是不管是初始位置还是开始走的时候)
问最多可以放多少个机器人,并且初始条件下在黑色格子的机器人最多有多少个。
本题思路:
首先我们要把输入处理下来,都转化为1维数组的形式,下标都从1开始。
我们思考:要求任何时候都不允许有两个机器人在同一个格子上的情况。
我们可以假设放置上去的机器人走了nm个格子,如果这些机器人在nm个格子之后的位置不是在同一个位置,就说明他们不会相遇了。因为nm个格子是所给的总共的格子,已经走完一遍了,下一遍就是循环了。
在nm个格子中,相遇了就会一直相遇,没相遇就再也不会遇见。
所以我们可以处理nm一个循环的格子。
用nex[][]保存,nex[i][j]表示第i + 1次从j走到的目的地。(i从0开始,所以是i+1次)
如果不同开始位置的机器人的目的地相同,那么我们只能选取一个机器人,因为题目要求最多的黑色格子,所以我们尽可能选取从黑色格子出发的机器人。
之后我们要模拟 n * m 的过程,看看n * m步到达的目的地是哪里
因为nm最大是1e6,这里需要用到倍增。
用倍增的话1e6的数据最多处理20次。(二进制的最大位数)
所以我们处理好20次的模拟过程。记录每一个格子的下一步是哪里
倍增思路就是从大到小。(因为从小到大可能出现“悔棋”现象,我在LCA里面有详细说明)
走n * m步进行分割,看看每一次最多走多少步。(步数分析需要二进制下考虑)
b[i] = 1表示当前i这个格子是从黑色格子走过来的。
w[i] = 1表示当前i这个格子是从白色格子走过来的。
从当前格子开始走n*m步走到哪里去,目的地to需要标记。标记要参考初始位置的格子颜色,为黑就标记黑色,为白就标记白色。
(这里有情况是初始位置不相同,目的地相同的情况,需要注意到)
之后我们再跑一遍,如果当前标记为黑色的格子,我们就black++,ans++。特别注意b[i] = w[i] = 0;都需要标记为0;因为有可能目的地是一个地方,初始位置不一样,我们只能选取其中的一种,我们黑色的格子优先选择。
好啦~解释完啦
对了,我们memset有tle了。。。。啊!!所以我直接在维护答案的时候直接初始化了。
代码部分:
#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 1e6 + 10;
int n, m;
int color[N];
char s[N];
int nex[24][N];
int w[N], b[N];
int main()
{
int t;
cin >> t;
while (t--)
{
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf ("%s", s + 1);
for (int j = 1; j <= m; j++)
{
color[(i - 1) * m + j] = (s[j] == '1');
}
}
for (int i = 1; i <= n; i++)
{
scanf ("%s", s + 1);
for (int j = 1; j <= m; j++)
{
int to;
if (s[j] == 'U')
{
to = (i - 2) * m + j;
}
else if (s[j] == 'D')
{
to = i * m + j;
}
else if (s[j] == 'R')
{
to = (i - 1) * m + j + 1;
}
else
{
to = (i - 1) * m + j - 1;
}
nex[0][(i - 1) * m + j] = to;
}
}
n *= m;
for (int i = 1; i <= 20; i++)
{
for (int j = 1; j <= n; j++)
{
nex[i][j] = nex[i - 1][nex[i - 1][j]];
}
}
for (int j = 1; j <= n; j++)
{
int to = j;
for (int i = 20; ~i; i--)//此循环到达-1结束,-1取反为0
{
if ((1 << i) & n)//走了nm步,用倍增从大往小
{
to = nex[i][to];
}
}
color[j] ? w[to] = 1 : b[to] = 1;
}
int ans = 0;
int blac = 0;
for (int i = 1; i <= n; i++)
{
if (b[i])
{
b[i] = w[i] = 0;
blac++;
ans++;
}
else if (w[i])
{
w[i] = 0;
ans++;
}
}
cout << ans << " " << blac << endl;
}
return 0;
}