1. 程式人生 > >bzoj 2832 宅男小c

bzoj 2832 宅男小c

 
Description

眾所周知,小C是個宅男,所以他的每天的食物要靠外賣來解決。小C現在有M元錢,他想知道這些錢他最多可以吃多少天。

 

餐廳提供N種食物,每種食物有兩個屬性,單價Pi和保質期Si,表示小C需要花Pi元才能買到足夠一天吃的這種食物,並且需要在送到Si天內吃完,否則食物會變質,就不能吃了,若Si為0則意味著必須在送到當天吃完。另外,每次送餐需要額外F元送餐費。

 

Input

每個測試點包含多組測試資料; 每個測試資料第一行三個整數M,F,N,如題目描述中所述;
以下N行,每行兩個整數,分別表示PiSi

Output

對於每個測試資料輸出一行,表示最多可以吃的天數。

Sample Input

32 5 2
5 0
10 2
10 10 1
10 10
10 1 1
1 5

Sample Output

3
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 }
View Code