BZOJ3874 [Ahoi2014&Jsoi2014]宅男计划

题面在这里

首先发现有一些食物是没用的(贵一些,保质期反而短),去掉

这样剩下都是\(s\)\(p\)递增的

同时考虑到每次叫外卖是独立的过程,那么每次点的食物应该是一样的

如果知道叫k次外卖,显然能取便宜食物就取,贪心得到最多天数

然后这个天数应该是关于k的一个单峰函数,三分即可

示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn=205;
int n,N; ll m,f;
struct data{
ll s,p;
inline bool operator<(const data&b)const {return s<b.s;}
}a[maxn],b[maxn];
ll calc(ll k){
ll M=m-k*f,res=0,day=0,t;
for (int i=1;i<=n;i++){
if (a[i].s>=day)
t=min(a[i].s-day+1,M/a[i].p/k),day+=t,res+=t*k,M-=t*k*a[i].p;
if (a[i].s>=day)
t=M/a[i].p,day++,res+=t,M-=t*a[i].p;
}
return res;
}
int main(){
scanf("%lld%lld%d",&m,&f,&N);
for (int i=1;i<=N;i++) scanf("%lld%lld",&b[i].p,&b[i].s);
for (int i=1;i<=N;i++){
bool suc=1;
for (int j=1;j<=N;j++)
if (b[i].p>b[j].p&&b[i].s<b[j].s) {suc=0;break;}
if (suc) a[++n]=b[i];
}
sort(a+1,a+1+n);
ll l=1,r=m/f,ans=0;
while (l<=r){
ll mid1=l+(r-l)/3,mid2=r-(r-l)/3,c1=calc(mid1),c2=calc(mid2);
ans=max(ans,max(c1,c2));
if (c1<c2) l=mid1+1;else r=mid2-1;
}
printf("%lld",ans);
return 0;
}