bzoj2424 [HAOI2010]订货 dp+单调性

时间:2023-11-16 16:40:20

[HAOI2010]订货

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1311  Solved: 884
[Submit][Status][Discuss]

Description

某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定第一月月初的库存量为零,第n月月底的库存量也为零,问如何安排这n个月订购计划,才能使成本最低?每月月初订购,订购后产品立即到货,进库并供应市场,于当月被售掉则不必付存贮费。假设仓库容量为S。

Input

第1行:n, m, S (0<=n<=50, 0<=m<=10, 0<=S<=10000)
第2行:U1 , U2 , ... , Ui , ... , Un (0<=Ui<=10000)
第3行:d1 , d2 , ..., di , ... , dn (0<=di<=100)

Output

只有1行,一个整数,代表最低成本

Sample Input

3 1 1000
2 4 8
1 2 4

Sample Output

34

HINT

先写了个DP方程:f[i][j]=min(f[i][j],f[i-1][k]+d[i]*(j+u[i]-k)+m*k);(0<=j<=s,0<=k<=j+u[i])

  O(n*s^2),T的结果很明显

  优化一下,很容易发现其实f数组是具有一定的单调性的

  那么用单调队列来优化一下下

  当f[i-1][list[head]]+d[i]*(j+u[i]-list[head])+m*list[head]>f[i-1][list[head+1]]+d[i]*(j+u[i]-list[head+1])+m*list[head+1]的时候说明list[head+1]对于当前情况更优,所以head++,不过要判断一下list[head+1]是否<=j+u[i]

  其实f[i-1][list[head]]+d[i]*(j+u[i]-list[head])+m*list[head]>f[i-1][list[head+1]]+d[i]*(j+u[i]-list[head+1])+m*list[head+1]

  可以转化为f[i-1][list[head]]-(d[i]-m)*list[head]>f[i-1][list[head+1]]-(d[i]-m)*list[head+1],将其中不变的值去掉

 #include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio> #define N 57
#define M 10007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m,s;
int u[],d[];
int f[][];
int list[]; int main()
{
n=read(),m=read(),s=read();
for(int i=;i<=n;i++) u[i]=read();
for(int i=;i<=n;i++) d[i]=read();
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=n;i++)
{
int head=,tail=s+;
for(int j=;j<=s;j++) list[j+]=j;
for(int j=;j<=s;j++)
{
while(head<=tail&&f[i-][list[head]]-(d[i]-m)*list[head]>f[i-][list[head+]]-(d[i]-m)*list[head+]&&list[head+]<=j+u[i]) head++;
int k=list[head];
f[i][j]=f[i-][k]+d[i]*(j+u[i]-k)+m*k;
}
}
printf("%d\n",f[n][]);
}