题解:qoj9564 Hey, Have You Seen My Kangaroo?
题意:给你一个操作序列和一个地图,初始每个没有障碍的位置上都有一个袋鼠,无限循环地操作这个操作序列,每一次所有的袋鼠都会同时向一个方向走一步,在同一个位置的袋鼠会合并,问对于 \(i=1,2\cdots n\times m\),需要多久可以使袋鼠数量 \(\le i\)。
做法:
首先我们发现循环操作这个事情不太好弄,我们就直接算出来做完一整次操作序列后每个位置会到哪里,那么会形成一颗基环树。
我们发现,对于每个节点,设他到子树内的节点距离最大时 \(x\),那么前 \(x+1\) 轮的时候我们都会有节点传上来,并且每一轮的合并是一样的。
那么我们考虑直接枚举第一轮的合并,那么后若干轮每轮都会重复这一轮的一些合并。
我们先预处理出来每个格子在第多少轮内都有袋鼠,然后考虑一次合并带来的影响,假设两个格子有的时间分别是 \(x,y\),那么 \(\min(x,y)\) 的时间内他们都会有一个袋鼠在这里合并,计算即可。注意合并玩之后要把他们的标记改为 \(\max(x,y)\),因为在 \(\max(x,y)\) 的时间内都会有袋鼠贡献过来。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int n, m, k;
string s[maxn], opt;
int id(int x, int y) {
return (x - 1) * m + y;
}
struct node {
int x, y;
};
vector<node> v[maxn];
int to[maxn], cir[maxn], vis[maxn], cnt;
vector<int> e[maxn];
void dfs(int x, int col) {
vis[x] = col;
if(!vis[to[x]])
dfs(to[x], col);
else if(vis[to[x]] == col){
int p = x;
do {
cir[p] = 1;
p = to[p];
// cout << p << endl;
} while(p != x);
}
// cout << x << endl;
}
int h[maxn], ans[maxn];
void get_h(int x) {
h[x] = 1;
for (int i = 0; i < e[x].size(); i++) {
int v = e[x][i];
if(cir[v])
continue;
get_h(v);
h[x] = max(h[v] + 1, h[x]);
}
}
int tim[maxn], tot;
int nwh[maxn], th[maxn], rest;
int main() {
cin >> n >> m >> k >> opt; opt = ' ' + opt;
for (int i = 1; i <= n; i++)
cin >> s[i], s[i] = ' ' + s[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m + 1; j++)
v[i].push_back(node{0, 0});
for (int j = 1; j <= m; j++) {
if(s[i][j] == '1')
v[i][j] = {i, j}, cnt++;
}
}
for (int i = 1; i <= k; i++) {
for (int x = 1; x <= n; x++)
for (int y = 1; y <= m; y++) {
if(s[x][y] == '0')
continue;
if(opt[i] == 'U') {
if(v[x][y].x != 1 && s[v[x][y].x - 1][v[x][y].y] != '0')
v[x][y].x--;
}
else if(opt[i] == 'D') {
if(v[x][y].x != n && s[v[x][y].x + 1][v[x][y].y] != '0')
v[x][y].x++;
}
else if(opt[i] == 'L') {
if(v[x][y].y != 1 && s[v[x][y].x][v[x][y].y - 1] != '0')
v[x][y].y--;
}
else {
if(v[x][y].y != m && s[v[x][y].x][v[x][y].y + 1] != '0')
v[x][y].y++;
}
}
// cout << v[2][2].x << " " << v[2][2].y << endl;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if(v[i][j].x)
to[id(i, j)] = id(v[i][j].x, v[i][j].y), e[to[id(i, j)]].push_back(id(i, j));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if(s[i][j] == '1' && !vis[id(i, j)])
dfs(id(i, j), id(i, j));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if(cir[id(i, j)])
get_h(id(i, j)), h[id(i, j)] = 2e9;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
nwh[id(i, j)] = h[id(i, j)];
// cout << h[id(i, j)] << " " << i << " " << j << " " << cir[id(i, j)] << " " << to[id(i, j)]<< endl;
}
}
for (int i = 1; i <= k; i++) {
memset(th, 0, sizeof(th));
// if(i == 36) {
// for (int x = 1; x <= n; x++)
// for (int y = 1; y <= m; y++)
// cout << nwh[id(x, y)] << (y == m ? '\n' : ' ');
// }
for (int x = 1; x <= n; x++)
for (int y = 1; y <= m; y++) {
if(s[x][y] == '0')
continue;
int ID = id(x, y), to;
if(opt[i] == 'U') {
if(x != 1 && s[x - 1][y] != '0')
to = ID - m;
else
to = ID;
// cout << x << " " << y << " " << ID - m << " " << ID << endl;
}
else if(opt[i] == 'D') {
if(x != n && s[x + 1][y] != '0')
to = ID + m;
else
to = ID;
}
else if(opt[i] == 'L') {
if(y != 1 && s[x][y - 1] != '0')
to = ID - 1;
else
to = ID;
}
else {
if(y != m && s[x][y + 1] != '0')
to = ID + 1;
else
to = ID;
}
int d = min(th[to], nwh[ID]);
for (int t = 0; t < d; t++)
tim[++tot] = k * t + i;
th[to] = max(th[to], nwh[ID]);
// cout << to << " " << ID << " " << th[to] << " " << << endl;
}
for (int x = 1; x <= n; x++)
for (int y = 1; y <= m; y++)
nwh[id(x, y)] = th[id(x, y)];
}
sort(tim + 1, tim + tot + 1);
for (int i = n * m; i >= cnt; i--)
ans[i] = 0;
for (int i = 1; i <= tot; i++)
ans[cnt - i] = tim[i];
for (int i = cnt - tot - 1; i >= 1; i--)
ans[i] = -1;
for (int i = 1; i <= n * m; i++)
cout << ans[i] << endl;
return 0;
}

浙公网安备 33010602011771号