【BZOJ2832&&3874】宅男小C [模拟退火][贪心]
2017-03-13 14:47
246 查看
宅男小C
Time Limit: 10 Sec Memory Limit: 256 MB[Submit][Status][Discuss]
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 25 0
10 2
10 10 1
10 10
10 1 1
1 5
Sample Output
30
8
HINT
对于40%的数据,M,Si <= 2*10^6;
对于100%的数据,1 ≤ N ≤ 200,M, Si<= 10^18,1 ≤ T ≤ 50,1 ≤ F ≤ M,1 ≤ Pi ≤ M。
Main idea
每种食物有一个花费和一个保质期,在保质期内食用可以多活一天,每次购买可以买多个食物,买一次会耗费一些钱,问最多能活几天。Solution
我们先从简单的做法入手,如果确定了购买次数,能求出最多活几天吗?答案是显然可以的。我们运用贪心:首先,若存在某种价格又贵保质期又短的食物显然是没有用的,我们sort一遍直接删去,然后我们可以得到一个价格上升且保质期上升的序列。我们基于这里开始贪心:我们先从便宜的食物入手,显然每次都是从这种食物吃起,仅存在两种不购买便宜的情况:1.保质期过了;2.钱不够满足所有次数了。如果保质期过了,我们就选择下一个食物,如果钱不够满足所有次数了,那就能买几次买几次,记录一下答案,退出。
我们解决了确定购买次数最多活几天之后,再仔细思考:由于购买会花钱,那么我们大胆猜测购买次数和活的天数有一定的规律,我们画了几张图之后,发现其比例大致单峰,如下图所示:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> using namespace std; typedef long long s64; const int ONE = 10005; const int INF = 2147483640; int n; s64 A,Now,Ans; s64 Total,F; struct power { s64 cost; s64 days; }a[ONE]; bool cmp(const power &a,const power &b) { if(a.cost == b.cost) return a.days > b.days; return a.cost < b.cost; } int get() { int res=1,Q=1; char c; while( (c=getchar())<48 || c>57) if(c=='-')Q=-1; if(Q) res=c-48; while((c=getchar())>=48 && c<=57) res=res*10+c-48; return res*Q; } void pre() { sort(a+1,a+n+1,cmp); s64 d=-1; int m=n; n=0; for(int i=1;i<=m;i++) if(a[i].days > d) a[++n]=a[i], d=a[i].days; } s64 Judge(s64 times) { if(times<=0) return 0; s64 Money = Total - times * F; s64 res = 0, num, day = 0; for(int i=1;i<=n;i++) { num = min(Money / a[i].cost / times, a[i].days - day + 1); Money -= num * a[i].cost * times; day += num; res += times * num; if(day <= a[i].days) { num = Money / a[i].cost; res += num; Ans = max(Ans, res); return res; } } Ans = max(Ans, res); return res; } double Random() {return rand()/(double)RAND_MAX;} void SA(double T) { Now = 1; while(T >= 1) { A = Now + (s64)(T * (Random()*2-1)) ; if(A<=0) A = T*Random(); s64 dE = Judge(A) - Judge(Now); if(dE > 0) Now = A; T *= 0.93; } } void Solve() { for(int i=1;i<=n;i++) scanf("%lld %lld",&a[i].cost,&a[i].days); pre(); Ans = 0; SA(Total / F + 1); printf("%lld\n",Ans); } int main() { while(scanf("%lld %lld %d",&Total,&F,&n) != EOF) Solve(); }View Code
相关文章推荐
- 【BZOJ3874】[Ahoi2014]宅男计划【贪心】【模拟退火 / 三分法】
- BZOJ 3874([Ahoi2014]宅男计划-dp+三分法+贪心)
- hdoj I can do it! 3552 (贪心&模拟)
- Codeforces ABBYY Cup 3.0 / 316A1 316A2 Special Task(模拟&贪心&组合数学)
- hdu4393 Throw nails【优先队列&&贪心&&模拟】
- Codeforces Round #428 (Div. 2)-贪心&模拟-B. Game of the Rows
- [三分 贪心] BZOJ 3874 [Ahoi2014]宅男计划
- BZOJ 3874: [Ahoi2014]宅男计划 三分+贪心
- [BZOJ2832][宅男小C][模拟退火]
- CSU-ACM2017暑期训练7-模拟&&贪心 E - 荷马史诗 HYSBZ - 4198
- [BZOJ3680]吊打XXX && 模拟退火
- POJ 1379 Run away & POJ 2420 A star not a Tree [模拟退火] [爬山算法]
- CSU-ACM2017暑期训练7-模拟&&贪心 A - Radar Installation POJ - 1328
- JZOJ4726. 【NOIP2016提高A组模拟8.22】种花(2017.8DP&贪心专题)
- 【CodeForces】508C - Anya and Ghosts(贪心 & 模拟)
- CSU-ACM2017暑期训练7-模拟&&贪心A - Radar Installation
- LeetCode 之模拟&贪心
- JZOJ5220. 【GDOI2018模拟7.10】C(2017.8DP&贪心专题)
- CSU-ACM2017暑期训练7-模拟&&贪心 F - Sokoban
- 通用局部搜索算法之模拟退火[转]