LINK

考虑上下界网络流

每个点拆分为入点 i n i in_i ini和出点 o u t i out_i outi

新建源点 s s s,新建汇点 t t t

s s s连向每个入点流量为 [ 0 , i n f ] [0,inf] [0,inf],边权 p p p的边,代表买纸巾

每个出点向 t t t连流量 [ 0 , i n f ] [0,inf] [0,inf],边权 0 0 0的边,代表不洗纸巾

o u t i out_i outi i n i + n in_{i+n} ini+n连流量 [ 0 , i n f ] [0,inf] [0,inf]边权 s s s的边,代表这天用完的纸巾去慢洗

o u t i out_i outi i n i + m in_{i+m} ini+m流量 [ 0 , i n f ] [0,inf] [0,inf],边权 f f f的边,代表这天用完的纸巾去快洗

i n i in_i ini o u t i out_i outi连流量 [ r i , i n f ] [r_i,inf] [ri,inf]的边,代表这天至少需要 r i r_i ri的纸巾

然后还有一条边非常容易忘记,就是当纸巾在第 k k k天洗好,其实是可以留到下一天再用的

i n i in_i ini i n i + 1 in_{i+1} ini+1连流量 [ 0 , i n f ] [0,inf] [0,inf]边权 0 0 0的边,代表把纸巾留到下一天

如此一来,我们建立了一个有源汇上下界网络图

t t t s s s连一条流量 [ 0 , i n f ] [0,inf] [0,inf]边权 0 0 0的边补齐循环流

然后引入 s s , t t ss,tt ss,tt,补齐对图中所有点的流量,由 s s ss ss t t tt tt跑一发最小费用流

得到的就是可行流中最小的费用

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 1e9;
const int maxn = 2e5+10;
int in[maxn],out[maxn],N,s,t,ss,tt;
int p,n,m,fval,sval;
struct edge{
	int to,nxt,flow,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int l,int r,int w)
{
	in[v] +=l, out[u] += l;
	d[++cnt] = ( edge ){ v,head[u],r-l,w}, head[u] = cnt;
	d[++cnt] = ( edge ){ u,head[v],0,-w},head[v] = cnt;
}
int flow[maxn],pre[maxn],dis[maxn],vis[maxn];
bool spfa(int s,int t)
{
	for(int i=0;i<=t;i++) dis[i] = inf, vis[i] = 0;
	queue<int>q; dis[s] = 0, flow[s] = inf, q.push( s ); 
	while( !q.empty() )
	{
		int u = q.front(); q.pop();
		vis[u] = 0;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v = d[i].to;
			if( d[i].flow&&dis[u]+d[i].w<dis[v] )
			{
				dis[v] = dis[u]+d[i].w;	flow[v] = min( flow[u],d[i].flow); pre[v] = i;
				if( !vis[v] )	vis[v] = 1, q.push( v );
			}
		}
	}
	return dis[t]!=inf;
}
int dinic(int s,int t)
{
	int ans = 0;
	while( spfa(s,t) )
	{
	//	cout << "哈哈哈\n";
		int x = t, i; ans += flow[t]*dis[t];
		while( x!=s )
		{
			i = pre[x];
			d[i].flow -= flow[t], d[i^1].flow += flow[t];
			x = d[i^1].to;
		}
	}
	return ans;
}
signed main()
{
	cin >> N;
	s = N+N+1, t = s+1, ss = t+1, tt = ss+1;
	for(int i=1,x;i<=N;i++)	cin >> x, add( i,i+N,x,inf,0 );
	cin >> p >> m >> fval >> n >> sval;
	for(int i=1;i<=N;i++)
	{
		add(s,i,0,inf,p );//新的餐巾纸 
		add(i+N,t,0,inf,0 );//流回汇点 
		if( i<N )	add(i,i+1,0,inf,0);//留给下一天 
		if( i+m<=N )	add(i+N,i+m,0,inf,fval);//块洗 
		if( i+n<=N )	add(i+N,i+n,0,inf,sval);//慢洗 
	}
	add(t,s,0,inf,0);//循环流
	for(int i=1;i<=t;i++)
	{
		if( in[i]>out[i] )	add(ss,i,0,in[i]-out[i],0);
		else	add(i,tt,0,out[i]-in[i],0);
	}
	cout << dinic(ss,tt);
}