其他分享
首页 > 其他分享> > 「MCOI-05」追杀 - 题解

「MCOI-05」追杀 - 题解

作者:互联网

Description

Solution

16pts

暴力模拟即可。

枚举 \(i, v\) 然后 \(O(n)\) 统计剩余玩家数量,时间复杂度 \(O(n^2m)\)。

57pts

我们发现穿越之后的模拟追杀过程很难优化,于是可以考虑优化穿越次数。

我们不希望进行两次结果相同的穿越,例如对于 \([(1, 2), (2, 3), (1, 3)]\),插入 \((0, 1)\) 到四个不同的位置,结果不变。

考虑在 \((u_i, v_i)\) 前插入怎样的追杀不会导致结果相同。

于是 \(u_i, v_i\) 之前只需要尝试追杀 \(u_i\),时间复杂度降为 \(O(n^2)\)。

当然这档部分分也可以用暴力+比较好的剪枝水过

100pts

再次观察发现,如果 \(u_i\) 或 \(v_i\) 已经非公认活着,那么所有穿越都无效。

考虑到每位玩家只有三滴血,所以最多只需要穿越 \(3m\) 次,时间复杂度复杂度降为 \(O(nm)\)。

Code

#include <bits/stdc++.h>
using namespace std;

const int L = 1e5 + 5; 
int n, m, cnt, tmp, u[L], v[L], a[L], b[L], ans[L], las[L];
bool f[L];

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d %d", &u[i], &v[i]);
	
	for (int j = 1; j <= m; j++)
		b[j] = 3;
	
	for (int j = 1; j <= n; j++)
		if (b[u[j]] != 0 && b[v[j]] != 0)
			b[v[j]]--, f[j] = true;
	
	for (int i = 1; i <= m; i++)
		if (b[i] != 0) tmp++;
		
	for (int i = 1; i <= n; i++) {
		if (!f[i]) continue;
		cnt = 0;
			
		for (int j = 1; j <= m; j++)
			a[j] = 3;
			
		for (int j = 1; j <= n; j++) {
			if (i == j && a[u[i]] != 0)
				a[u[i]]--;
					
			if (a[u[j]] != 0 && a[v[j]] != 0) a[v[j]]--;
		}
		
		for (int j = 1; j <= m; j++)
			if (a[j] != 0) cnt++;
			
		ans[cnt] += i - las[u[i]];
		las[u[i]] = i;
	}
	
	for (int i = 1; i <= m; i++)
		ans[tmp - (b[i]==1)] += n + 1 - las[i];
	
	for (int i = 0; i <= m; i++)
		printf("%d ", ans[i]);
	
	return 0;
}

标签:le,MCOI,05,int,题解,复杂度,玩家,追杀,穿越
来源: https://www.cnblogs.com/SparkleZH-Blog/p/14729801.html