[CF 848B] Rooter's Song 二维弹性碰撞
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF 848B] Rooter's Song 二维弹性碰撞相关的知识,希望对你有一定的参考价值。
题意
在平面直角坐标系中, 有一个以 (0, 0) 为左下角, (w, h) 为右上角的矩形.
有 n 个人, 它们一开始站在 x 轴或者 y 轴上, 第 i 个人的坐标为 $p_i$ , 准备跳舞.
对于第 i 个人, 它最开始会在原地站立 t 秒, 然后朝着矩形的对面跳舞, 每 1s 跳 1 个单位长度.
如果两个人相遇了, 那么它们会相互走另一个人的路线.
人们会一直走着, 直到它们到达了矩形的某个边界.
问每个人最后会走到的坐标.
分析
二维弹性碰撞.
大致地思路是先回顾一维弹性碰撞, 然后再拓展到二维.
我们考虑两个人什么时候会碰撞.
设第一个人的参数为 $p_1, t_1$ , 从 y 轴向右出发.
设第二个人的参数为 $p_2, t_2$ , 从 x 轴向上出发.
$p_1 + t_2 = p_2 + t_1$ .
$p_1 - t_1 = p_2 - t_2$ .
设 $D_i = p_i - t_i$ , $D_i$ 相同的可能会发生碰撞, $D_i$ 不同的一定不会发生碰撞.
一维弹性碰撞规律1: 如果忽略个体之间的差异, 碰撞相当于没有碰撞.
同样可以用到二维弹性碰撞.
所以我们可以得知所有最后的坐标.
一维弹性碰撞规律2: 如果不忽略个体之间的差异, 那么相对顺序不变.
一维弹性碰撞的相对顺序就是 x 轴.
观察一下, 发现二维弹性碰撞的相对顺序由二元组 (x, -y) , 即先尽可能让 x 小, 再让 y 大.
综上, 我们根据 p-t 进行分组, 然后求出组内最终的坐标并进行排序, 再将组内的人按照 (x, -y) 排序, 然后一一对应.
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <algorithm> 6 #include <vector> 7 using namespace std; 8 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 9 inline int rd(void) { 10 int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1; 11 int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f; 12 } 13 14 const int N = 100005; 15 16 int n, w, h; 17 int g[N], p[N], t[N]; 18 19 int Hash[N], tot; 20 inline int Find(int w) { return lower_bound(Hash+1, Hash+tot+1, w) - Hash; } 21 22 struct point { 23 int x, y, id; 24 friend inline bool operator < (point A, point B) { return A.x != B.x ? A.x < B.x : A.y > B.y; } 25 }; 26 vector<point> End[N], Lis[N]; 27 28 point Go[N]; 29 30 int main(void) { 31 #ifndef ONLINE_JUDGE 32 freopen("D.in", "r", stdin); 33 #endif 34 35 n = rd(), w = rd(), h = rd(); 36 F(i, 1, n) 37 g[i] = rd(), p[i] = rd(), t[i] = rd(), Hash[++tot] = p[i] - t[i]; 38 39 sort(Hash+1, Hash+tot+1); 40 tot = unique(Hash+1, Hash+tot+1)-Hash-1; 41 42 F(i, 1, n) { 43 int Belong = Find(p[i] - t[i]); 44 if (g[i] == 1) { 45 End[Belong].push_back((point){p[i], h, 0}); 46 Lis[Belong].push_back((point){p[i], 0, i}); 47 } 48 else { 49 End[Belong].push_back((point){w, p[i], 0}); 50 Lis[Belong].push_back((point){0, p[i], i}); 51 } 52 } 53 54 F(i, 1, tot) { 55 sort(End[i].begin(), End[i].end()); 56 sort(Lis[i].begin(), Lis[i].end()); 57 for (vector<point>::iterator itE = End[i].begin(), itL = Lis[i].begin(); itE != End[i].end(); itE++, itL++) 58 Go[itL -> id] = *itE; 59 } 60 61 F(i, 1, n) 62 printf("%d %d\n", Go[i].x, Go[i].y); 63 64 return 0; 65 }
以上是关于[CF 848B] Rooter's Song 二维弹性碰撞的主要内容,如果未能解决你的问题,请参考以下文章
codeforces 848B Rooter's Song 思维题
排序规律Codeforces Round #254 (Div. 2) - D. Rooter's Song