[USACO14DEC] Cow Jog G 题解

文章讲述了如何确定在无限跑道上,不同起始位置和速度的奶牛在跑步过程中不会发生位置冲突所需的最少跑道数量。通过分析奶牛的追及问题,提出了两种解决方案:一是利用二分查找和单调性质插入奶牛,二是采用贪心策略结合二分查找划分终点子序列。两种方法都关注于避免在限定时间内奶牛位置重叠的情况。
摘要由CSDN通过智能技术生成

原题题面

Farmer John 的 N N N 头奶牛 ( 1 ≤ N ≤ 1 0 5 ) ( 1\leq N ≤ 10^5 ) (1N105) 正在一条长度无限的跑道上慢跑,每头奶牛都有一个不同的开始位置,以及不同的跑步速度。

为了方便奶牛们互相超越,整个跑道被分成了若干条赛道。在同一时刻,不可能有在同一条赛道上的两头奶牛占据相同的位置。

现在奶牛们要跑 T T T 分钟,在跑步过程中,他们不会改变自己所在的赛道和自己跑步的速度。FJ想要知道,为了奶牛间不会发生冲突,他需要至少准备多少条赛道。

Farmer John’s N N N cows ( 1 ≤ N ≤ 100 , 000 ) (1 \leq N \leq 100,000) (1N100,000) are out exercising their
hooves again, jogging along an infinite track. Each cow starts at a
distinct position on the track, and some cows run at different speeds.

The track is divided into lanes so that cows may move past each other.
No two cows in the same lane may ever occupy the same position.
Farmer John doesn’t want any cow to have to change lanes or adjust
speed, and he wonders how many lanes he will need to accomplish this
if the cows are going to run for T T T minutes ( 1 ≤ T ≤ 1 0 9 ) . (1 \leq T \leq 10^9). (1T109).

输入格式

The first line of input contains N N N and T T T.

The following N N N lines each contain the initial position and speed of a
single cow. Position is a nonnegative integer and speed is a positive
integer; both numbers are at most 1 billion. All cows start at
distinct positions, and these will be given in increasing order in the
input.

第一行包括两个整数 N N N T T T 。接下来 N N N 行,每行两个整数 p i p_i pi v i v_i vi ( p i , v i ≤ 1 0 9 ) (p_i, v_i ≤ 10^9 ) (pi,vi109),分别代表奶牛的初始位置和速度。

保证了初始位置不相同且为升序排列。

输出格式

A single integer indicating the minimum number of lanes necessary so
that no two cows in the same lane ever occupy the same location
(including at time T T T).

一个整数,代表最少需要的跑道数目。

样例

样例输入

5 3
0 1
1 2
2 3
3 2
6 1

样例输出

3

题解 1

怎样判断一个奶牛是否会追上另外一头奶牛?

设奶牛甲起点是 x 1 x_1 x1 ,速度是 y 1 y_1 y1 米每分钟,奶牛乙起点是 x 2 x_2 x2 ,速度是 y 2 y_2 y2 米每分钟,我们想一想乙怎样才能追上甲?

前提是 $x_1>x_2 $,这是显然的,要是甲在乙后面,那显然是甲在追乙。

现在再想想,上述条件满足的情况下,乙什么时候能追上甲?我们易得:
x 1 − x 2 y 2 − y 1 \frac{x_1-x_2}{y_2-y_1} y2y1x1x2

题目规定了一个时间上限,所以我们得到一个不等式,以判断乙是否能追上,追上的条件是:
x 1 − x 2 y 2 − y 1 ≤ t \frac{x_1-x_2}{y_2-y_1}\leq t y2y1x1x2t

变形得:

x 1 + t × y 1 ≤ x 2 + t × y 2 x_1+t\times y_1\leq x_2+t\times y_2 x1+t×y1x2+t×y2

这是本题一个重要的性质。

现在我们给奶牛从大到小排个序,这样前提就满足了。

对于每个奶牛,我们设想前面的奶牛都没有冲突了,当前奶牛我们可以找一个合适的跑道加入,否则就再修一个。

对于每个跑道,记录最小的 x + t × y x+t\times y x+t×y ,和当前奶牛比对,不难发现在这个过程中跑道的最小值始终具有单调性,所以可以二分查找,就这样不断插入奶牛即可。

代码实现 1

#include<bits/stdc++.h>
using namespace std;
inline long long read() {
    char c = getchar();
    long long sum = 0,f=1;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') {
        f = -1;
        c = getchar();
    }
    do {
        sum = (sum << 3) + (sum << 1) + c - '0';
        c = getchar();
    } while (c >= '0' && c <= '9');
    return sum * f;
}
long long n,t,x,y,a[100005],b[100005],cnt,l,r,ans,mn[100005];
int main()
{
    n=read(),t=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read(),b[i]=read();
    }
    for(int i=n;i>=1;i--)
    {
        x=a[i],y=b[i];
        l=1,r=cnt,ans=0;
        while(l<=r)
        {
            long long mid=(l+r)/2;
            if(x+t*y<mn[mid])
            {
                r=mid-1;
                ans=mid;
            }
            else
            {
                l=mid+1;
            }
        }
        if(ans==0)cnt++,ans=cnt;
        mn[ans]=x+t*y;
    }
    printf("%lld",cnt);
}

题解 2

今天教练又出了一次这道题,我们考虑用另外一种思考方式得到贪心策略。

首先我们可以想一下,对于每个奶牛相当于从 p i p_i pi 匀速运动至 p i + T × v i p_i+T\times v_i pi+T×vi

我们思考两个奶牛怎么样会碰到,首先后面的奶牛记为 j j j,则 j j j 超过 i i i 肯定需要 v j > v i v_j>v_i vj>vi

但是本题在时间上也有限制我们发现由于速度限制,如果 j j j 超过了 i i i,后面 i i i 不可能再追上 j j j,所以我们不妨算出终点进行比较。

由于起点递增,所以我们相当要保证满足 i ≤ j , p j + T × v j ≤ p i + T × v i i\leq j,p_j+T\times v_j\leq p_i+T\times v_i ij,pj+T×vjpi+T×vi ( i , j ) (i,j) (i,j) 不在同一组。

因此每一组都应该满足 i ≤ j , p i + T × v i ≤ p j + T × v j i\leq j, p_i+T\times v_i\leq p_j+T\times v_j ij,pi+T×vipj+T×vj

发现其实就是把终点划分成最少的上升子序列,这就是一个拦截导弹问题了,可以用贪心加上二分维护。

时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

代码实现

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=3e5+5;
LL n,k,a[N],b[N],cnt,s[N];
int main()
{
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld%lld",&a[i],&b[i]);
		b[i]=a[i]+b[i]*k;
	}
	for(int i=1;i<=n;i++)
	{
		LL l=1,r=cnt,ans=0;
		while(l<=r)
		{
			LL mid=(l+r)/2;
			if(s[mid]<b[i])ans=mid,r=mid-1;
			else l=mid+1;
		}
		if(ans==0)ans=++cnt;
		s[ans]=b[i];
	}
	printf("%lld",cnt);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值