【题解】【CodeForces653F】Ants on a Circle

题目链接

点击打开链接

题目解法

先观察蚂蚁运动的方式(observation),可以发现下面几件事情:

  1. 蚂蚁的顺序不变。
  2. 蚂蚁最终所在位置就是“两只蚂蚁相遇后穿透”的最终位置。所以可以得出蚂蚁最终在哪些位置。

所以现在可以知道蚂蚁的最终位置与蚂蚁的顺序。但是满足最终位置和顺序的蚂蚁位置方案数有 (n) 种(因为是环,所以可以转 (n) 下)。所以需要知道最终结果对应的是哪一种。

现在定义一个环对应的排列是这样的:从 0 开始顺时针向后每一个蚂蚁的编号。那么只要一只蚂蚁从位置 m-1 走到了位置 0 ,那么排列就会向右轮换一下。如果一只蚂蚁从位置 0 走到了位置 m-1 ,那么排列会向左轮换一下。所以只需要求出每只蚂蚁顺着/倒着穿过了 0 多少次,这个次数其实与“蚂蚁相遇后穿过”顺着、倒着穿过 0 的次数等价。这样就可以求出到底是哪一个轮换了。那就做完了。

总结

  • 整体考虑轮换(宏观思考),而不要想着求一个蚂蚁最终的位置(虽然可以做,但是特别麻烦)(微观思考)。

代码

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
ll n, m, pp[N], ans[N];
ll t;
struct ANT {
	ll pos, dir, id;
	bool operator < (const ANT &d) const { return pos < d.pos; }
} ant[N];
ll Get(ll x) {
	if (ant[x].dir == -1) {
//		if (t >= ant[x].pos && ant[x].pos != 0)
//			return ((t - ant[x].pos) / m + 1);
//		else if (ant[x].pos == 0)
//			return (t - ant[x].pos) / m;
//		else return 0; 
		return (t - ant[x].pos + m - 1) / m;
	} else {
		if (t >= m - ant[x].pos)
			return -((t - (m - ant[x].pos)) / m + 1);
		else return 0;
//		return - (t + ant[x].pos) / m;
	}
}
int main() {
	scanf("%lld%lld%lld", &n, &m, &t);
	for (ll i = 0; i < n; ++i) {
		scanf("%lld", &ant[i].pos);
		--ant[i].pos;
		char dd = getchar();
		while (dd == ' ') dd = getchar();
		ant[i].dir = (dd == 'L') ? -1 : 1;
		ant[i].id = i;
	}
	sort(ant, ant + n);
	for (ll i = 0; i < n; ++i)
		pp[i] = ((t * ant[i].dir + ant[i].pos) % m + m) % m;
	sort(pp, pp + n);
	ll bg = 0;
	for (ll i = 0; i < n; ++i)
		bg = (Get(i) + bg) % n;
	bg = (bg + n) % n;
	for (ll i = bg, j = 0; j < n; ++j, i = (i + 1) % n)
		ans[ant[i].id] = pp[j];
	for (ll i = 0; i < n; ++i)
		printf("%lld ", ans[i] + 1);
	printf("
");
	return 0;
}
原文地址:https://www.cnblogs.com/YouthRhythms/p/13326862.html