原题
题目大意
有n只牛运货,要运到0粮仓和l粮仓里,如果两头牛碰面,那么它们各自回头走,运完一半就停止
题目分析
这题在比赛的时候没有做出来……主要是因为不知道怎么帮牛找回自己的包袱。
很明显的是,两头牛相碰的时候可以当作穿过去,他们的重量交换,这个数据规模不能直接跑模拟,所以要二分找结束时间,结束时间也不难找,主要还是怎么帮牛牛找回自己的包袱。
后来发现,不管牛牛怎么相碰,运到的重量还是按照其坐标离终点先后来运达的,所以我对它们进行了一次按x升序排序,然后二分检查两边各到了多少头牛,再把包袱分配下去就行了。
最后就是找出有多少次相遇,只需将走完后的序列和走前的序列对比,对每只向左走的牛跨越了多少只牛就是答案了(重叠也是个问题……我看了一下别人的,最方便的好像就是各加0.1了)
代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
typedef struct cow
{
int num;
int w;
double x;
int d;
};
cow all[50011];
int index[50011];
int pt = 0,nt = 0,reach = 0,sumw = 0,endt;
int n,L;
bool cmpx(cow a,cow b)
{
return a.x < b.x;
}
bool check(int x)
{
int lb = 0,rb = 0;
for (int i = 0;i < n;++i)
{
int t = all[i].x + all[i].d * x;
if (t <= 0) ++lb;
if (t >= L) ++rb;
}
int tot = 0;
for (int i = 0;i < lb;++i) tot += all[i].w;
for (int i = 0;i < rb;++i) tot += all[n - i - 1].w;
if (tot * 2 >= sumw) return true;
else return false;
}
int main()
{
int ans = 0;
scanf("%d%d",&n,&L);
for (int i = 0;i < n;i++)
{
int w,x,d;
scanf("%d%d%d",&w,&x,&d);
sumw += w;
all[i].w = w,all[i].x = x,all[i].num = i,all[i].d = d;
}
std::sort(all,all + n,cmpx);
for (int i = 0;i < n;++i) index[all[i].num] = i;
int l = 0,r = L;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid)) r = mid - 1;else l = mid + 1;
}
for (int i = 0;i < n;++i)
if (all[i].d == 1) all[i].x += l + 0.1;else all[i].x -= l + 0.1;
std::sort(all,all + n,cmpx);
for (int i = 0;i < n;++i)
if (all[i].d == 1) ans += abs(index[all[i].num] - i);
printf("%d",ans);
return 0;
}