仍然对“为什么这个函数单峰”的问题毫无理解
首先,对于保质期又低、价格又贵的食物,我们显然不需要购买它。所以如果设(pri_i)表示保质期不小于(i)的所有食品中价格最低的食品的价格,那么(pri)数组显然单调不降。
考虑如果我们要直接去做比较麻烦,可是如果我们知道点外卖的次数,就很好计算了。
假设我们知道了我们总共要买(x)次外卖,不难知道这(x)次外卖点的食物能够坚持的时间的极差不会超过(1),否则可以用多的补少的,在不降低总坚持时间的情况下降低总价格(因为(pri)单调不降)。
假设(x)次外卖坚持的时间为(K)与(K+1),那么可以先二分出(K),然后将剩下的钱尽可能多的买(pri_{K+1})。
现在,确定点外卖的次数就可以求得对应的能够坚持的时间,问题就是如何求最长的时间。不难发现点外卖的次数与坚持的时间对应的函数是一个单峰函数,直接上三分就完事了。
有没有神仙会证这个函数单峰啊QAQ
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#define INF 0x3f3f3f3f
#define int long long
#define PII pair < int , int >
#define st first
#define nd second
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return f ? -a : a;
}
vector < PII > tg;
vector < PII > :: iterator it , it1;
int M , F , N , sum[210];
bool f[210];
inline int calcSum(int dir){
it = lower_bound(tg.begin() , tg.end() , PII(dir , -1));
int t = it - tg.begin();
if(t && !f[t - 1] || (t ? sum[t - 1] : 0) + 1.0 * tg[t].nd * (dir - (t ? tg[t - 1].st : -1)) > M)
return 2e18;
return (t ? sum[t - 1] : 0) + tg[t].nd * (dir - (t ? tg[t - 1].st : -1));
}
inline int calc(int x){
int s = M - x * F , L = -1 , R = tg[N - 1].st;
while(L < R){
int mid = L + R + 1 >> 1;
calcSum(mid) <= s / x ? L = mid : R = mid - 1;
}
s -= calcSum(L) * x;
if(L == tg[N - 1].st)
return (L + 1) * x;
it = lower_bound(tg.begin() , tg.end() , PII(L + 1 , -1));
return (L + 1) * x + s / it->second;
}
inline bool check(int mid){
return calc(mid) >= calc(mid + 1);
}
signed main(){
#ifndef ONLINE_JUDGE
//freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
M = read();
F = read();
N = read();
for(int i = 1 ; i <= N ; ++i){
int a = read() , b = read();
tg.push_back(PII(b , a));
}
sort(tg.begin() , tg.end());
for(it = --tg.end() , it1 = it , --it1 ; it != tg.begin() ; --it , it1 = it , --it1)
if(it->nd < it1->nd)
it1->nd = it->nd;
for(it = tg.begin() , it1 = it , ++it1 ; it1 != tg.end() ; ++it , it1 = it , ++it1)
if(it->st == it1->st)
it1->nd = it->nd;
for(int i = 0 ; i < N ; ++i)
if((i == 0 ? 0 : sum[i - 1]) + 1.0 * tg[i].nd * (tg[i].st - (i == 0 ? -1 : tg[i - 1].st)) <= M){
f[i] = 1;
sum[i] = (!i ? 0 : sum[i - 1]) + tg[i].nd * (tg[i].st - (!i ? -1 : tg[i - 1].st));
}
else
break;
int L = 1 , R = M / F;
while(L < R){
int mid = (L + R) >> 1;
check(mid) ? R = mid : L = mid + 1;
}
cout << calc(L);
return 0;
}