快被二分搞死了。。。听一个大神说最好选择一种适合自己的写法然后搞懂它。
一开始用昨天那种写法,发现姿势不对,于是跑去又重新搞了一遍二分写法的区别。
题意:
现在告诉你每个点i的高度的求法是si=A+B*(i-1);然后有n次询问,对于每次询问我们给出l,t,m,分别代表起点l,然后是最多可以吃的次数t,每次最多可以吃掉几个食物m。
每次吃一个食物只能把每个食物的高度减少1。然后问你在满足上述的条件的情况下,我们最多可以吃到终点在哪儿的食物,也就是找到r。注意,我们必须把所有的食物都吃到高度为0才可以!
思路:
我们可以用二分来求终点r,然后再进行判断。
判断:
1)首先是最大的高度要小于天数,要不然最大的那个高度不可能被减少完。
2)因为总共可以进行减少m*t次,所以所有序列的和要小于等于m*t才可以。
还有注意一点就是要用__int64,要不然会错。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
#define maxn 1000010
typedef __int64 ll;
ll A,B,n;
ll l,t,m;
bool is_ok(ll mid){
ll hmax=A+B*(mid-1);
if(hmax>t) return false;
ll sum=0;
ll a1=A+B*(l-1);
ll a2=A+B*(mid-1);
sum=(a1+a2)*(mid-l+1)/2;
if(sum>m*t) return false;
return true;
}
ll bin(ll x,ll y){
ll mid;
ll ans=-1;
while(x<y){
mid=x+(y-x)/2;
if(is_ok(mid)){
x=mid+1;
ans=max(ans,mid); //二分的时候可以用一个变量来保存结果!
}
else y=mid;
}
return ans;
}
int main(){
scanf("%I64d%I64d%I64d",&A,&B,&n);
while(n--){
scanf("%I64d%I64d%I64d",&l,&t,&m);
ll ans=bin(l,maxn+1);
if(ans<l||ans>1000000) printf("-1\n");
else printf("%I64d\n",ans);
}
}
/*
2 1 4
1 5 3
3 3 10
7 10 2
6 4 8
*/