NOI 2393:Yogurt factory【2019北大推免E】
-
总时间限制:
1000ms
-
内存限制:
65536kB
-
描述
The cows have purchased a yogurt factory that makes world-famous Yucky Yogurt. Over the next N (1 <= N <= 10,000) weeks, the price of milk and labor will fluctuate weekly such that it will cost the company C_i (1 <= C_i <= 5,000) cents to produce one unit of yogurt in week i. Yucky’s factory, being well-designed, can produce arbitrarily many units of yogurt each week. Yucky Yogurt owns a warehouse that can store unused yogurt at a constant fee of S (1 <= S <= 100) cents per unit of yogurt per week. Fortuitously, yogurt does not spoil. Yucky Yogurt’s warehouse is enormous, so it can hold arbitrarily many units of yogurt. Yucky wants to find a way to make weekly deliveries of Y_i (0 <= Y_i <= 10,000) units of yogurt to its clientele (Y_i is the delivery quantity in week i). Help Yucky minimize its costs over the entire N-week period. Yogurt produced in week i, as well as any yogurt already in storage, can be used to meet Yucky’s demand for that week.
-
输入
- Line 1: Two space-separated integers, N and S. * Lines 2…N+1: Line i+1 contains two space-separated integers: C_i and Y_i.
-
输出
- Line 1: Line 1 contains a single integer: the minimum total cost to satisfy the yogurt schedule. Note that the total might be too large for a 32-bit integer.
-
样例输入
4 5 88 200 89 400 97 300 91 500
-
样例输出
126900
-
提示
OUTPUT DETAILS: In week 1, produce 200 units of yogurt and deliver all of it. In week 2, produce 700 units: deliver 400 units while storing 300 units. In week 3, deliver the 300 units that were stored. In week 4, produce and deliver 500 units.
题解
-
子问题:dp[i]:完成week[:i]的所有demand需要的最少cost
-
证明最优子结构(假设问题的最优解不蕴含子问题的最优解,即子问题存在更优的解):dp[i]是完成week[:i]的所有demand需要的最少cost,其中完成week[:i-1]的所有demand需要的cost部分,假设不是最优(即不满足最优子结构性质),即存在更低的完成week[:i-1]的所有demand需要的cost,则这个更优解和dp[i]中完成week[i]的demand部分可以组合成问题dp[i]的最优解,与最优性矛盾
-
-
更新:dp[i]=dp[i-1]+选择week[:i]中在week[i]时单价最低的week生产本周的所有demand
- week[j]在week[i]时单价:cost[j]+S*(i-j) (初始生产的单价,加上每周存储的单价)
- note:
- dp[i]对于dp[:i-1]只需要知道dp[i-1],因此可以省略数组使用变量dp
- 更新对于当前week week[i],week[:i]的单价:(考虑从week[i-1]来的关系)
- cost[j]+S*(i-j) = cost[j]+S*(i-1-j) +S
- 进一步发现,所有之前已经有单价的单价都是同步+S,因此进入新的一周,最低price一定是min((原先的最低price+S), 新周的price)
- 进一步的,这样的话cost也不用数组存了
- 看到可以用在week[i-1]的单价来获取week[i]的单价,避免乘法
- cost[j]+S*(i-j) = cost[j]+S*(i-1-j) +S
-
初始:dp[0]:前面没有周,必须本周完成demand,因此dp[0]=c[0]*d
-
时间复杂度:对于week[i]常数操作,因此复杂度是O(n),N<=104<1-9是可以的
-
数据范围:
- 全周代价C*Y*N=5000*104*104 = 5*1011>2*109用int不行要用long long
- 单价:1 <= C_i <= 5,000,1 <= S <= 100,1 <= N <= 10,000,则最大单价5000+100*10000<10^9,可以用int,不过和demand乘法时需要是long long乘法,所以建议用long long
#define MAXN 10005
int main()
{
int N,S;
cin>>N>>S;
long long d,c;//demand, cost
cin>>c>>d;//N>=1, this must be safe
long long dp=c*d;
long long min_price=c;
for(int i=1; i<N; ++i){
cin>>c>>d;
//update min_price
min_price=min(c,min_price+S);
//update dp
dp += min_price*d;
}
cout<<dp<<endl;
return 0;
}