题目链接
题目解法
先观察蚂蚁运动的方式(observation),可以发现下面几件事情:
- 蚂蚁的顺序不变。
- 蚂蚁最终所在位置就是“两只蚂蚁相遇后穿透”的最终位置。所以可以得出蚂蚁最终在哪些位置。
所以现在可以知道蚂蚁的最终位置与蚂蚁的顺序。但是满足最终位置和顺序的蚂蚁位置方案数有 (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;
}