这题用zkw是真的快……洛谷原先是卡了普通费用流的……但是现在时间到4s了,又有o2和高性能,貌似普通的费用流也可以过了,首先,要把每一天和源点汇点建一条容量为每天的需求的边,费用为0,然后在条件满足的情况下(i + n < num of days之类的),向快洗之后那天建容量INF费用f的边,慢洗也是,注意要和下一天建边,容量INF费用0,因为可以不洗……所以还是要拆点,至于新买的,自然费用为price,容量inf,总结一下:
1、从source向每个xi连一条容量为ri,费用为0的有向边
2、从每个yi向sink连一条容量为ri,费用为0的有向边
3、从source向每个yi连一条容量为INF,费用为p的有向边
4、从每个xi向xi+1(i+1<=day)连一条容量为INF,费用为0的有向边(有餐巾会留到明天)
5、从每个xi向yi+m(i+m<=day)连一条容量为INF,费用为f的有向边
6、从每个xi向yi+n(i+n<=day)连一条容量为INF,费用为s的有向边
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <functional>
#include <queue>
using namespace std;
int cnt=1,nd,price,m,f,n,s,ans;
bool inq[2005];
const int INF = 0x3f3f3f3f;
const int MAXN = 80003;
const int MAXE = 160003;
struct Edge {
int from, to, nxt, cap, flow, cost;
Edge() {}
Edge(int from, int to, int nxt, int cap, int flow, int cost):from(from), to(to), nxt(nxt), cap(cap), flow(flow), cost(cost) {}
}e[MAXE];
int h[MAXN], p;
int source, sink;
int cur[MAXN];
int d[MAXN];
queue<int> q;
bool exist[MAXN];
inline void add_edge(int x, int y, int cap, int cost) {
e[p] = Edge(x, y, h[x], cap, 0, cost); h[x] = p++;
e[p] = Edge(y, x, h[y], 0, 0, -cost); h[y] = p++;
}
bool SPFA() {
memset(d, 0x3f, sizeof(d));
memset(exist, 0, sizeof(exist));
memset(cur, -1, sizeof(cur));
q.push(source);
d[source] = 0;
exist[source] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
exist[u] = 0;
for(int i = h[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if(e[i].cap > e[i].flow && d[v] > d[u] + e[i].cost) {
d[v] = d[u] + e[i].cost;
cur[v] = i;
if(!exist[v]) {
q.push(v);
exist[v] = 1;
}
}
}
}
return d[sink] != INF;
}
long long MCMF() {
long long cost = 0;
while(SPFA()) {
int flow = INF;
for(int i = sink; i != source; i = e[cur[i]].from) flow = min(flow, e[cur[i]].cap - e[cur[i]].flow);
for(int i = sink; i != source; i = e[cur[i]].from) {
e[cur[i]].flow += flow;
e[cur[i] ^ 1].flow -= flow;
}
cost += flow * d[sink];
}
return cost;
}
int main()
{
memset(h, -1, sizeof(h));
scanf("%d", &nd);
int x;source = 0; sink = 8000;
for(int i = 1; i <= nd; i++)
{
scanf("%d",&x);
add_edge(source, i, x, 0);//连源点汇点
add_edge(nd + i, sink, x, 0);
}
scanf("%d%d%d%d%d", &price, &m, &f, &n, &s);
for(int i = 1; i <= nd; i++)
{
if(i + 1 <= nd)add_edge(i, i + 1, INF, 0);//留到明天
if(i + m <= nd)add_edge(i, nd + i + m, INF, f);//快洗
if(i + n <= nd)add_edge(i, nd + i + n, INF, s);//慢洗
add_edge(source, nd+i, INF, price);//新买
}
printf("%d\n",MCMF());
return 0;
}