[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

「CF80A」Panoramix's Prediction

CF718EMatvey's Birthday BFS+动态规划

CF 1912 A NEKO's Maze Game

CF1279D Santa's Bot