D — Circular Dance
题目大意:
两个谷仓位于一维数轴上的位置0和L(1≤L≤109)。也有N头牛(1≤N≤5*104)在不同的地点在数轴上的。每头奶牛i最初位于xi的某个位置,以每秒1单位的速度向正或负方向移动,用整数di表示,di为1或- 1。每头奶牛的体重wi也在范围[1,103]内。所有的奶牛总是以恒定的速度移动,直到下列事件之一发生:如果奶牛i到达谷仓,那么奶牛i停止移动。当两头牛i和j占据了同一个地方,而那个地方不是谷仓时,在这种情况下,奶牛i与j速度交换。注意,奶牛可能会在非整数的点相遇。
当进入谷仓的所有牛的重量之和至少是所有牛的重量之和的一半时,所用时间记为T。请确定在时间0…T范围内(包括时间T),两对牛的总相遇次数。
输入
第一行包含两个以空格分隔的整数N和L。
接下来的N行分别包含三个以空格分隔的整数wi、xi和di。所有的位置xi都是不同的,并且满足0<xi<L.
输出
只有一行,相遇对数。
题目分析:
两头奶牛相遇时交换速度可以看作互相穿过交换体重了,所以向左的有几头牛,最后就有几头牛归向0,向右的有几头牛,最后就有几头牛归向L。所以,对位置排序的奶牛,如果有n头牛,x头牛向左走,y头牛向右走。那么前x个重量一定会归向0位置,后y个重量会归为L位置。离谷仓最近的奶牛肯定先进,就可以算出时间T了。算出在无限时间的相遇对数和T内未相遇的对数,两个数值相减即答案。
代码实现:
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
struct cow
{
int w,x,d,t;
double x1;
}a[50010],b[50010],c[50010];
bool cmp1(cow x,cow y)
{
if (x.x==y.x) return x.d>y.d;
return x.x<y.x;
}
bool cmp2(cow x,cow y)
{
return x.t<y.t;
}
bool cmp3(cow x,cow y)
{
return x.x1<y.x1;
}
int main()
{
int n,len;
int ans = 0, ans0 = 0;
int sum = 0, sum_wight = 0, wight = 0;
int m_i = 0, s = 0;
int time = 0;
int l,r;
scanf("%d%d",&n,&len);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d", &a[i].w, &a[i].x, &a[i].d);
sum_wight += a[i].w;
}
sort(a+1,a+n+1,cmp1);
for(int i=1; i<=n; i++){ //无限时间相遇次数ans
if(a[i].d==1) sum++;
else ans += sum;
}
for(int i=1; i<=n; i++) //为了找出先进入谷仓的重量
{
if(a[i].d==-1) b[i].t = a[i].x;
else b[i].t = len-a[i].x;
b[i].x = a[i].x;
b[i].d = a[i].d;
}
sort(b+1,b+n+1,cmp2); //排序,越靠前越先进入谷仓
l = 1;
r = n;
for(int i=1; i<=n; i++) //算出时间T,即time
{
if(b[i].d==1)
{
wight += a[r].w;
r--;
}
else
{
wight += a[l].w;
l++;
}
if(wight*2>=sum_wight)
{
m_i = i+1;
time = b[i].t;
break;
}
}
for(int i=m_i; i<=n; i++)
{
if (b[i].t>time)
{
s++;
if(b[i].d==1) c[s].x1 = b[i].x+time+0.1; //错开相遇点
else c[s].x1 = b[i].x-time-0.1;
c[s].d = b[i].d;
}
}
sort(c+1,c+s+1,cmp3);
sum = 0;
for(int i=1; i<=s; i++){
if(c[i].d==1) sum++;
else ans0 += sum;
}
printf("%d\n",ans-ans0);
return 0;
}
最后希望路过的dl给予改进建议!
来源:CSDN
作者:csdn_xieql
链接:https://blog.csdn.net/csdn_xieql/article/details/104441495