YbtOj练习:二分2 最小时间

http://noip.ybtoj.com.cn/contest/15/problem/2

这道题写了快一个早上   卑微

因为通过其他量来确定时间太难,所以我们可以先确定时间,在来判定该方案是否合法。即答案转化为二分判定。

对于每一种确定的选法,它的收益都是一个一次函数,要么单调递增要么单调递减。若单调递减,只要t=0可行就可行,若此时不行就一定不行(答案保证有解),而单调递增时,我们需要二分找到最早的符合要求的时刻。因此,对于每一个确定的时间,我们只需要先判定0是否是最优解,若不是再进行二分,二分时每次让答案累加前m大的value即可(小于零的数不要加!!记得判定!!)

而这时就出现了新的问题,如果每一次都重新排序的话,会TLE。  而实际上我们需要的并不是一个有序的数组,我们只需要前m大的数字就行,因此就可以用nth_element函数来实现(我上一篇博客写了)

代码如下

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m,l,r=1e9;
ll S;
struct node{
    int k,b;
    ll val;
    bool operator < (const node &G) const
    {
        return val>G.val;
    }
}a[N];
bool check(int x)
{
    for(int i=0;i<n;i++) a[i].val=a[i].k*x+a[i].b;
    ll res=0ll;
    nth_element(a,a+m,a+n);
    for(int i=0;i<m;i++) 
    {
        if(a[i].val>0)  //一开始忘了写,卡了半天!! 
        res+=a[i].val;
        if(res>=S) return true;
    }
    return false;
}
signed main()
{
    scanf("%lld%lld%lld",&n,&m,&S);
    for(int i=0;i<n;i++) scanf("%lld%lld",&a[i].k,&a[i].b);
    if(check(0))
    {
        printf("0");
        return 0;
    }
    while(l<r)
    {
        int mid=l+r>>1;
        if(!check(mid)) l=mid+1;
        else r=mid;
    }
    printf("%lld",l);
    return 0;
}

 注意这道题要开long long

posted @ 2020-08-10 10:47  Gold_stein  阅读(249)  评论(0编辑  收藏  举报