bzoj2424 [HAOI2010]订货 dp+单调性
[HAOI2010]订货
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
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],将其中不变的值去掉
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define N 57 8 #define M 10007 9 using namespace std; 10 inline int read() 11 { 12 int x=0,f=1;char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 14 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 18 int n,m,s; 19 int u[51],d[51]; 20 int f[51][11000]; 21 int list[11000]; 22 23 int main() 24 { 25 n=read(),m=read(),s=read(); 26 for(int i=1;i<=n;i++) u[i]=read(); 27 for(int i=1;i<=n;i++) d[i]=read(); 28 memset(f,63,sizeof(f)); 29 f[0][0]=0; 30 for(int i=1;i<=n;i++) 31 { 32 int head=1,tail=s+1; 33 for(int j=0;j<=s;j++) list[j+1]=j; 34 for(int j=0;j<=s;j++) 35 { 36 while(head<=tail&&f[i-1][list[head]]-(d[i]-m)*list[head]>f[i-1][list[head+1]]-(d[i]-m)*list[head+1]&&list[head+1]<=j+u[i]) head++; 37 int k=list[head]; 38 f[i][j]=f[i-1][k]+d[i]*(j+u[i]-k)+m*k; 39 } 40 } 41 printf("%d\n",f[n][0]); 42 }