codeforces 848B Rooter's Song
正解:排序+模拟。
我们注意到两个点碰撞的必要条件,$pi+tj=pj+ti$,移项以后发现就是$pi-ti=pj-tj$,那么我们可以把$p-t$相同的点分为同一组。
然后我们还可以发现一点,就是无论两个点怎样碰撞,原来被覆盖的路径都是不会改变的。然后我们再观察一下样例的那张图。
可以发现,一个点最后是横向还是纵向与它碰撞的横向点和纵向点的数量大小关系有关。
以一个纵向点为例,如果与它一组的横坐标在它后面的纵向点数量$>=$所有和它一组的横向点数量,那么它就会变成横向点,否则就会变成一个纵向点。
于是我们对于每一个组按照横坐标和纵坐标来排序,就可以直接根据上述条件来判断一个点最终的位置,具体细节可以看一下代码。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define mp make_pair 6 #define x first 7 #define y second 8 #define N (200005) 9 10 using namespace std; 11 12 vector<pair<int,int> >vec[2][N]; 13 pair<int,int> ans[N]; 14 15 int n,w,h; 16 17 il int gi(){ 18 RG int x=0,q=1; RG char ch=getchar(); 19 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 20 if (ch=='-') q=-1,ch=getchar(); 21 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 22 return q*x; 23 } 24 25 int main(){ 26 #ifndef ONLINE_JUDGE 27 freopen("song.in","r",stdin); 28 freopen("song.out","w",stdout); 29 #endif 30 n=gi(),w=gi(),h=gi(); 31 for (RG int i=1,op,p,t;i<=n;++i){ 32 op=gi()-1,p=gi(),t=gi(); 33 vec[op][p-t+100000].push_back(make_pair(p,i)); 34 } 35 for (RG int i=1,sz1,sz2;i<=200000;++i){ 36 sort(vec[0][i].begin(),vec[0][i].end()); 37 sort(vec[1][i].begin(),vec[1][i].end()); 38 sz1=vec[0][i].size(),sz2=vec[1][i].size(); 39 for (RG int j=0;j<sz1;++j) 40 if (sz1-j-1>=sz2) ans[vec[0][i][j].y]=mp(vec[0][i][j+sz2].x,h); 41 else ans[vec[0][i][j].y]=mp(w,vec[1][i][sz1-j-1].x); 42 for (RG int j=0;j<sz2;++j) 43 if (sz2-j-1>=sz1) ans[vec[1][i][j].y]=mp(w,vec[1][i][j+sz1].x); 44 else ans[vec[1][i][j].y]=mp(vec[0][i][sz2-j-1].x,h); 45 } 46 for (RG int i=1;i<=n;++i) printf("%d %d\n",ans[i].x,ans[i].y); return 0; 47 }