题目描述
Bessie's birthday is coming up, and she wishes to celebrate for the next D (1 <= D <= 100,000; 70% of testdata has 1 <= D <= 500) days. Cows have short attention spans so Bessie wants to provide toys to entertain them. She has calculated that she will require T_i (1 <= T_i <= 50) toys on day i.
Bessie's kindergarten provides many services to its aspiring bovine programmers, including a toy shop which sells toys for Tc (1 <= Tc <= 60) dollars. Bessie wishes to save money by reusing toys, but Farmer John is worried about transmitting diseases and requires toys to be disinfected before use. (The toy shop disinfects the toys when it sells them.)
The two disinfectant services near the farm provide handy complete services. The first one charges C1 dollars and requires N1 nights to complete; the second charges C2 dollars and requires N2 nights to complete (1 <= N1 <= D; 1 <= N2 <= D; 1 <= C1 <= 60; 1 <= C2 <= 60). Bessie takes the toys to the disinfecters after the party and can pay and pick them back up the next morning if one night service is rendered, or on later mornings if more nights are required for disinfecting.
Being an educated cow, Bessie has already learned the value of saving her money. Help her find the cheapest way she can provide toys for her party.
POINTS: 400
Bessie的生日快到了,她希望用D(1<=D<=100000)天来庆祝。奶牛们的注意力不会太集中,因此Bessie想通过提供玩具的方式来使它们高兴。她已经计算出了第i天需要的玩具数Ti(1<=Ti<=50).
Bessie的幼儿园给它们的奶牛程序员们提供了许多服务,包括一个每天以Tc(1<=Tc<=60)美元卖出商品的玩具店。Bessie想尽可能地节省钱。但是Farmer John担心没有经过消毒的玩具会带来传染病。(玩具店卖出的玩具是经过消毒)
有两种消毒的方式。第1种方式需要收费C1美元,需要N1个晚上的时间;第2种方式需要收费C2美元,需要N2个晚上的时间(1<=N1,N2<=D;1<=C1,C2<=60)。Bessie在派对结束之后把她的玩具带去消毒。如果消毒只需要一天,那么第二天就可以拿到;如果还需要一天,那么第三天才可以拿到。
作为一个受过教育的奶牛,Bessie已经了解到节约的意义。帮助她找到提供玩具的最便宜的方法。
输入格式
* Line 1: Six space-separated integers: D, N1, N2, C1, C2, Tc
* Lines 2..D+1: Line i+1 contains a single integer: T_i
输出格式
* Line 1: The minimum cost to provide safe and sanitary toys for Bessie's birthday parties.
输入输出样例
4 1 2 2 1 3 8 2 1 6
35
说明/提示
Bessie wishes to party for 4 days, and requires 8 toys the first day, 2 toys the second, 1 toy the third, and 6 toys on the fourth day. The first disinfectant service takes 1 day and charges 2, and the second takes 2 days and charges2,andthesecondtakes2daysandcharges1. Buying a new toy costs $3.
Day 1 Purchase 8 toys in the morning for $24; party in the
afternoon. Take 2 toys to the fast cleaner (overnight) and
the other 6 toys to the slow cleaner (two nights).
Day 2 Pick up the two toys at the fast cleaner; pay $4. Party in the afternoon. Take 1 toy to the slow cleaner.
Day 3 Pick up 6 toys from the slow cleaner and pay $6. Party in the afternoon.
Day 4 Pick up the final remaining toy from the slow cleaner
(bringing the number of toys onsite back to 6); pay $1. Party hearty with the realization that a minimum amount of money was spent
解:这是一道三分的题
1.三分性质证明 (引用hyhjulao 的证明)
设$f(x)$表示总花费 $g(x)$表示满足$f(x) $的情况下 消毒的花费
首先此式子满足递推式 $f[x]=x*Tc+g[x]$
进而化成函数 $f(x)=x*Tc+g(x)$
在这里证明此函数有峰值
注意到 $g(x-1)-g(x)>=g(x)-g(x+1) i $
转化为斜率可知这是$g(x)$是一个 斜率增大的函数
又因为 $f(x-1)-f(x) = g(x-1)-g(x)-Tc$ $ f(x)-f(x+1) = g(x)-g(x+1)-Tc$
于是我们有$ f(x) $是单峰或者单调函数
所以 想到三分
贪心部分
最先用慢洗的
然后用最近的快洗的
开三个双端队列维护即可
// #includeusing namespace std; // 1 fast 2 slow int C1,C2,N1,N2,D,Tc; #define maxnn 200000 #define inf 1000000000 int a[maxnn]; deque<int > Q; deque<int > mi; deque<int >mo; int calc(int mid) { int ans=mid*Tc; mi.clear(); mo.clear(); Q.clear(); for(int i=1;i<=D;i++) { int num=0; if(mid<=a[i]) { num=mid; mid=0; } else if(mid>a[i]) { mid=(mid-a[i]); num=a[i]; } while(Q.size()&&i-Q.front()>=N1) { mi.push_back(Q.front()); Q.pop_front(); } while(mi.size()&&i-mi.front()>=N2) { mo.push_back(mi.front()); mi.pop_front(); } while(num<a[i]) { if(mo.size()) { num++; mo.pop_front(); ans+=C2; } else if(mi.size()) { num++; mi.pop_back(); ans+=C1; } else { return inf; } } if(numreturn inf; for(int j=1;j<=a[i];j++) Q.push_back(i); } return ans; } int main() { int l=0; int r=0; scanf("%d%d%d%d%d%d",&D,&N1,&N2,&C1,&C2,&Tc); if(N1>N2) { swap(C1,C2); swap(N1,N2); } if(C1 C1; for(int i=1;i<=D;i++) { scanf("%d",&a[i]); r+=a[i]; } int rmid=(l+r)/2; int lmid=(rmid+l)/2; while(r-l>20) { rmid=(l+r)/2; lmid=(rmid+l)/2; int y=calc(rmid); if(y!=inf&&calc(rmid)>calc(lmid)) r=rmid; else { l=lmid+1; } } int ans=inf; for(int i=l;i<=r;i++) ans=min(ans,calc(i)); cout<<ans; }