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