bzoj 2832 宅男小c
Description
众所周知,小C是个宅男,所以他的每天的食物要靠外卖来解决。小C现在有M元钱,他想知道这些钱他最多可以吃多少天。
餐厅提供N种食物,每种食物有两个属性,单价Pi和保质期Si,表示小C需要花Pi元才能买到足够一天吃的这种食物,并且需要在送到Si天内吃完,否则食物会变质,就不能吃了,若Si为0则意味着必须在送到当天吃完。另外,每次送餐需要额外F元送餐费。
Input
每个测试点包含多组测试数据;
每个测试数据第一行三个整数M,F,N,如题目描述中所述;
以下N行,每行两个整数,分别表示Pi和Si。
Output
对于每个测试数据输出一行,表示最多可以吃的天数。
Sample Input
32 5 2
5 0
10 2
10 10 1
10 10
10 1 1
1 5
5 0
10 2
10 10 1
10 10
10 1 1
1 5
Sample Output
3
0
8
0
8
HINT
【数据规模及约定】
对于40%的数据,M,Si <= 2*10^6;
对于100%的数据,M, Si<= 10^18,1 ≤ T ≤ 50,1 ≤ F ≤ M,1 ≤ N ≤ 200,1 ≤ Pi ≤ M。
思路: 本题可以三分。
题解:
我不能确保这种方法的正确性,因为迄今为止我还没有看到其他能够复杂度能够承受的办法,最起码这样做的话,
数据是可以过的,当然不排除数据不够全面。因为送物品非常自由,没有任何限制,所以我们要找一个合适的自变
量进行枚举。可以发现,如果我们外卖的次数过少,那么就会出现一些食品性价比不高的情况;如果次数过多,
那么就会浪费外卖运费。故可以从这里入手,因为可以看出这是一个类似于二次函数的函数。我们可以通过三分来查找峰值。
那么对于每次的求值,就是以贪心为主体了。因为我们显然要价格便宜,保质期又长的食品,故我们将同保质期但
价格偏高的去除,然后根据保质期从大到小排序,我们给每一次送餐都加上一个该食品,直到钱不够或者时间已经超过。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define rep(i,a,b) for(R i=a;i<=b;i++) 5 #define Rep(i,a,b) for(R i=a;i>=b;i--) 6 #define ms(i,a) memset(a,i,sizeof(a)) 7 #define gc() getchar() 8 #define LL long long 9 typedef pair<LL,LL> pi; 10 template<class T>void read(T &x){ 11 x=0; char c=0; 12 while (!isdigit(c)) c=gc(); 13 while (isdigit(c)) x=x*10+(c^48),c=gc(); 14 } 15 int const N=210; 16 LL n,m,f,l,r,len,m1,m2,nn; 17 pi s1,s2,ans; 18 struct node{ 19 LL p,s; 20 }a[N]; 21 int cmp(node a,node b){ 22 return a.s==b.s? a.p<b.p: a.s> b.s; 23 } 24 25 pi calc(LL k){ 26 LL t=m-f*k,d=0,now=0,j; 27 Rep(i,nn,1){ 28 if(a[i].s>=d) j=min(t/a[i].p/k,a[i].s-d+1),d+=j,now+=j*k,t-=j*a[i].p*k; 29 if(a[i].s>=d) j=min(t/a[i].p,k),d++,now+=j,t-=j*a[i].p; 30 } 31 return pi(now,t); 32 } 33 34 int main(){ 35 while (scanf("%lld%lld%lld",&m,&f,&n)!=EOF){ 36 ans=pi(0,0); 37 rep(i,1,n) read(a[i].p),read(a[i].s); 38 sort(a+1,a+n+1,cmp);nn=1; 39 rep(i,2,n) if(a[nn].s>a[i].s && a[i].p<a[nn].p) a[++nn]=a[i]; 40 l=1,r=m/(f+a[nn].p); 41 while (l<=r){ 42 len=(r-l)/3; 43 if( (s1=calc(m1=l+len))>(s2=calc(m2=r-len))) ans=max(ans,s1),r=m2-1;else ans=max(ans,s2),l=m1+1; 44 } 45 cout<<ans.first<<endl; 46 } 47 return 0; 48 }