https://codeforces.com/group/5yyKg9gx7m/contest/269717/problem/D
分析:
依次取时间最小的,直到进仓质量为总的1/2,得到结束时间T。
算出一开始将要相遇的牛对数,和结束后,将要相遇的牛的对数,两个相减就是答案。
因为可能在T时刻,2头牛正好在同一处而又没有计算在相遇次数内。可以加减0.1让他们错位。因为至多有2头牛会在同一时刻停在同一位置。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <vector> #include <stack> using namespace std; typedef long long ll; const int maxn=5e4+6; struct cow { int w; int x; int d; int t; double cx;//错位后的x }c[maxn],c2[maxn]//c2是存一开始按位置排,最接近仓的牛; bool cmp1(struct cow a,struct cow b) { return a.x<b.x; } bool cmp3(struct cow a,struct cow b) { if(a.d==b.d) return a.x<b.x; return a.d<b.d; } bool cmp2(struct cow a,struct cow b) { return a.cx<b.cx; } int n,L; ll s; int T=0; void getT() { //得到T int mid=1; while(c[mid].d==-1) mid++;//有多少个向左走的 ll sum=0; int l=1,r=n; while(sum*2<s) { if((L-c[r].x>c[l].x&&l<mid)||r<mid) { sum+=c2[l].w;//这头牛的质量为相对接近终点的牛的质量 T=max(T,c[l].x); l++; } else { sum+=c2[r].w; T=max(T,L-c[r].x); r--; } } } int main() { cin>>n>>L; for(int i=1;i<=n;i++) { scanf("%d%d%d",&c[i].w,&c[i].x,&c[i].d); s+=c[i].w; if(c[i].d==1) c[i].t=L-c[i].x; else c[i].t=c[i].x; } sort(c+1,c+n+1,cmp1); memcpy(c2,c,sizeof c); int st=0; ll cnt1=0; ll cnt2=0; for(int i=1;i<=n;i++)//开始时有多少个要撞的 { if(c[i].x==0||c[i].x==L) continue; if(c[i].d>0) st++; else { if(st) { cnt1+=st; } } } sort(c+1,c+n+1,cmp3);//按d相同,x从小到大排,就是到达时间最短的牛 getT(); for(int i=1;i<=n;i++) //T时刻的位置 { if(c[i].x==0||c[i].x==L) continue; if(c[i].d>0) { if(c[i].x+T>=L) c[i].cx=L; else c[i].cx=c[i].x+T+0.1; } else { if(c[i].x-T<=0) c[i].cx=0; else c[i].cx=c[i].x-T-0.1; } } sort(c+1,c+n+1,cmp2); st=0; for(int i=1;i<=n;i++)//T时刻有多少个要撞的 { if(c[i].cx==0||c[i].cx==L) continue; if(c[i].d>0) st++; else { if(st) { cnt2+=st; } } } cout<<cnt1-cnt2<<endl; return 0; }
原文:https://www.cnblogs.com/studyshare777/p/12405196.html