题解: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;
}
posted @ 2025-08-04 13:36  LUlululu1616  阅读(28)  评论(1)    收藏  举报