餐巾

题目

传送门
一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。

(1)购买新的餐巾,每块需p分;
(2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(fm),费用需s分(s<f)。
在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。

INPUT

输入文件共 3 行,第 1 行为总天数;
第 2 行为每天所需的餐巾块数;
第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。

OUTPUT

一行,最小的费用

SAMPLE

INPUT

3
3 2 4
10 1 6 2 3

OUTPUT

64

解题报告

首先,每天的餐巾分为两种情况,新买的和原来的。
每天作为一个点,由S向其连边,容量为Ri,花费为0。
每天可以向T连边,容量为INF,花费为p,每天都可以购买餐巾无数次。
将每天用过的餐巾在新建一层点,由于分配去快洗和慢洗的餐巾总数有限制,并非分别有限制,所有这两种无需再分开,这层点分别向T建边,容量为Ri,花费为0,限制总容量。
使用快洗的餐巾,由i向(i+m+N)’建边,容量为INF,花费为f,慢洗同理,花费分别建边。
但第i-m天洗完后的餐巾也可以供第i天以后使用。所以再由i向i+1建边,容量为INF,花费为0。这样第i天就能使用到以前所有可以使用的洗完的餐巾了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct edge{
int e,n,flow,cost;
}a[20010];
int pre[410],tot;
inline void insert(int s,int e,int flow,int cost){
a[tot].e=e;
a[tot].flow=flow;
a[tot].cost=cost;
a[tot].n=pre[s];
pre[s]=tot++;
}
int S(0),T;
int N,p,m,f,n,s;
int r[201];
int flow(0),ans(0),inf(0x7fffffff);
inline void build(){
for(int i=1;i<=N;i++){
insert(S,i,r[i],0),insert(i,S,0,0);
insert(S,i+N,inf,p),insert(i+N,S,0,-p);
insert(i+N,T,r[i],0),insert(T,i+N,0,0);
if(i+m<=N)
insert(i,i+m+N,inf,f),insert(i+m+N,i,0,-f);
if(i+n<=N)
insert(i,i+n+N,inf,s),insert(i+n+N,i,0,-s);
if(i!=N)
insert(i,i+1,inf,0),insert(i+1,i,0,0);
}
}
int dis[410],fa[410],path[410];
inline bool bfs(){
memset(dis,30,sizeof(dis));
memset(fa,-1,sizeof(fa));
queue<int>q;
q.push(S);
dis[S]=0;
while(!q.empty()){
int k(q.front());
q.pop();
for(int i=pre[k];i!=-1;i=a[i].n){
int e(a[i].e);
if(a[i].flow&&dis[e]>dis[k]+a[i].cost){
dis[e]=dis[k]+a[i].cost;
fa[e]=k;
path[e]=i;
q.push(e);
}
}
}
if(fa[T]==-1)
return false;
return true;
}
inline void dinic(){
while(bfs()){
int f(inf);
for(int i=T;i!=S;i=fa[i])
if(a[path[i]].flow<f)
f=a[path[i]].flow;
flow+=f;
ans+=dis[T]*f;
for(int i=T;i!=S;i=fa[i]){
a[path[i]].flow-=f;
a[path[i]^1].flow+=f;
}
}
}
inline int gg(){
freopen("napkin.in","r",stdin);
freopen("napkin.out","w",stdout);
memset(pre,-1,sizeof(pre));
scanf("%d",&N);
T=(N<<1)+1;
for(int i=1;i<=N;i++)
scanf("%d",&r[i]);
scanf("%d%d%d%d%d",&p,&m,&f,&n,&s);
build();
dinic();
printf("%d",ans);
return 0;
}
int K(gg());
int main(){;}