【链接】h在这里写链接
【题意】
场上有 n
个点,它们分别向上与向右在不同时刻开始运动,相遇则改变移动方向,求最终这些点到达的坐标。
【题解】
先把每个点的坐标都往它本该移动的方向相反的方向退ti个单位。
这样,就相当于每个点都是同时开始运动的了。
想象一下,两个点同时碰撞的条件.
假设碰撞的点坐标为(x,y);
则初始的时候他们的坐标分别为(x-t,y)以及(x,y-t);
会发现,这两个点的x+y的值是一样的。
(这里的x,y是每个点都退ti个单位后的点x,y)
所以,能够发生碰撞的条件,就是x+y的值是一样的。
也即,他们同在一条直线y = -x + z上。
则我们把所有在同一条直线y = -x + z上的点都归为一组。
一组一组的处理。
(会发现,这组里面的点只会和组内部的点发生碰撞);
这些规律画图就很容易得到的。
然后,我们把这些点从左上到右下一个一个处理。
就能发现规律的。
会发现,左边,下边出来的点,都依照点的顺序投射到上,上右,右上,右下。
画图!别光看题解。
【错的次数】
0
【反思】
把每个点都往后移动。
抓住碰撞的条件是什么。
把点按照能碰撞的分为一组。
不难模拟出规律的。
【代码】
#include <bits/stdc++.h> using namespace std; const int N = 1e5; int n, w, h, g[N + 10], p[N + 10], t[N + 10]; pair <int, int> ans[N + 10]; map <int, vector<int> > dic; vector <int> vx, vy; void in() { cin >> n >> w >> h; for (int i = 1; i <= n; i++) { cin >> g[i] >> p[i] >> t[i]; dic[p[i] - t[i]].push_back(i); } } bool cmp(int x, int y) { return p[x] < p[y]; } void get_ans() { for (pair <int, vector<int> > temp : dic) { int len = temp.second.size(); for (int i = 0; i <= len - 1; i++) if (g[temp.second[i]] == 1) { vx.push_back(temp.second[i]); } else { vy.push_back(temp.second[i]); } sort(vx.begin(), vx.end(), cmp); sort(vy.begin(), vy.end(), cmp); int k = (int)vy.size() - 1 - (int)vx.size() + 1; k = max(k, 0); for (int i = (int)vy.size() - 1; i >= k; i--) { int temp = (int)vy.size() - i - 1; ans[vy[i]].first = p[vx[temp]], ans[vy[i]].second = h; } for (int i = k - 1; i >= 0; i--) { int temp = k - i; ans[vy[i]].first = w, ans[vy[i]].second = p[vy[(int)vy.size() - temp]]; } k = (int)vx.size() - 1 - (int)vy.size() + 1; k = max(k, 0); for (int i = (int)vx.size() - 1; i >= k; i--) { int temp = (int)vx.size() - i - 1; ans[vx[i]].first = w, ans[vx[i]].second = p[vy[temp]]; } for (int i = k - 1; i >= 0; i--) { int temp = k - i; ans[vx[i]].first = p[vx[(int)vx.size() - temp]], ans[vx[i]].second = h; } vx.clear(), vy.clear(); } } void out() { for (int i = 1; i <= n; i++) cout << ans[i].first << ' ' << ans[i].second << endl; } int main() { ios::sync_with_stdio(0), cin.tie(0); in(); get_ans(); out(); return 0; }