# Description
Luogu 传送门
# Solution
明显是要使用费用流,考虑如何建图。
把每一天拆成晚上和早上两个点,每天晚上会获得脏餐巾,早上会获得干净的餐巾。
- 从源点向每天晚上连流量为 ,费用为 0 的边,表示晚上会获得当天所需的 条脏餐巾。
- 从每天早上向汇点连流量为 ,费用为 0 的边,表示每天早上提供 条干净的餐巾给汇点,如果满流则合法。
- 从每天晚上向第二天的早上连流量为 ,费用为 0 的边,表示把当天的脏餐巾留给第二天。
- 快洗:第 天晚上向第 天早上连流量为 ,费用为 的边,表示从第 天开始洗,第 天能收到餐巾。
- 慢洗:同快洗。
- 购买:从源点向每天早上连一条流量为 ,费用为 的边,表示购买干净的餐巾。
注意连边的时候判一下边界。
#include <bits/stdc++.h> | |
#define int long long | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0; | |
char ch = getchar(); | |
while(!isdigit(ch)) ch = getchar(); | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x; | |
} | |
template <typename T> inline void write(T x){ | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 4010; | |
const int inf = 1e9; | |
const int INF = 1e18; | |
int n, m, t1, w1, t2, w2, s, t; | |
int a[N]; | |
struct node{ | |
int v, w, cost, nxt; | |
}edge[N * 15]; | |
int head[N], tot = 1; | |
inline void add(int x, int y, int z, int c){ | |
edge[++tot] = (node){y, z, c, head[x]}; | |
head[x] = tot; | |
} | |
inline void Add(int x, int y, int z, int c){ | |
add(x, y, z, c), add(y, x, 0, -c); | |
} | |
int dis[N], ans; | |
bool vis[N]; | |
inline bool spfa(){ | |
memset(vis, 0, sizeof(vis)); | |
memset(dis, 63, sizeof(dis)); | |
queue <int> q; | |
q.push(s), dis[s] = 0; | |
while(!q.empty()){ | |
int x = q.front(); q.pop(); | |
vis[x] = 0; | |
for(int i = head[x]; i; i = edge[i].nxt){ | |
int y = edge[i].v; | |
if(edge[i].w && dis[y] > dis[x] + edge[i].cost){ | |
dis[y] = dis[x] + edge[i].cost; | |
if(!vis[y]) vis[y] = 1, q.push(y); | |
} | |
} | |
} | |
return dis[t] < INF; | |
} | |
inline int dfs(int x, int lim){ | |
if(x == t || !lim) return lim; | |
int flow = 0; vis[x] = 1; | |
for(int i = head[x]; i; i = edge[i].nxt){ | |
int y = edge[i].v; | |
if(!vis[y] && edge[i].w && dis[y] == dis[x] + edge[i].cost){ | |
int res = dfs(y, min(lim, edge[i].w)); | |
lim -= res, flow += res, edge[i].w -= res, edge[i ^ 1].w += res, ans += 1ll * res * edge[i].cost; | |
} | |
} | |
return flow; | |
} | |
inline int solve(){ | |
while(spfa()) dfs(s, inf); | |
return ans; | |
} | |
signed main(){ | |
// freopen("P1251.in", "r", stdin); | |
// freopen("P1251.out", "w", stdout); | |
n = read(); | |
s = 0, t = 2 * n + 1; | |
for(int i = 1, x; i <= n; ++i) | |
x = read(), Add(s, i, x, 0), Add(i + n, t, x, 0); | |
m = read(), t1 = read(), w1 = read(), t2 = read(), w2 = read(); | |
for(int i = 1; i <= n; ++i){ | |
if(i + 1 <= n) Add(i, i + 1, inf, 0); | |
if(i + t1 <= n) Add(i, i + n + t1, inf, w1); | |
if(i + t2 <= n) Add(i, i + n + t2, inf, w2); | |
Add(s, i + n, inf, m); | |
} | |
write(solve()), puts(""); | |
return 0; | |
} |