网站子域名/宣传软文模板
传送门
题解:
注意到每天的需求和每天剩下的是独立的,也就是说相当于一开始每天都会新增riri个餐巾(从源点直接连(ri,0)(ri,0)),那么把需求点和剩余点分成两边,剩余点按照题目意思(待洗)向需求点连边即可。
因为可以购买,所以源点还要向需求点连边。
同时剩下的可以往后一个转移。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50,M=2e6+50,INF=0x3f3f3f3f;
inline int rd() {char ch=getchar(); int i=0,f=1;while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}return i*f;
}
int n,a[N],per,fs,fsv,sl,slv;
int g[N],nt[M],vt[M],w[M],v[M],ec=1;
int src,des,dis[N],vis[N],cur[N],vs;
int ans;
inline void add(int x,int y,int o,int q) {nt[++ec]=g[x]; g[x]=ec; vt[ec]=y; w[ec]=o; v[ec]=q;nt[++ec]=g[y]; g[y]=ec; vt[ec]=x; w[ec]=0; v[ec]=-q;
}
deque <int> q; int exi[N];
inline bool spfa() {while(!q.empty()) q.pop_front();memset(dis+1,0x3f,sizeof(int)*des);memset(exi+1,0,sizeof(int)*des);dis[src]=0; q.push_front(src);while(!q.empty()) {int u=q.front(); q.pop_front(); exi[u]=0;for(int e=g[u];e;e=nt[e]) {if(!w[e] || dis[vt[e]]<=dis[u]+v[e]) continue;dis[vt[e]]=dis[u]+v[e]; if(exi[vt[e]]) continue;if(q.size() && dis[q.front()]>dis[vt[e]]) q.push_front(vt[e]);else q.push_back(vt[e]);exi[vt[e]]=1;}} return dis[des]<INF;
}
inline int dinic(int x,int f,int cost) {if(x==des) {ans+=f*cost; return f;}int rs=0; vis[x]=vs;for(int &e=cur[x];e;e=nt[e]) {if(!w[e] || dis[vt[e]]!=dis[x]+v[e] || vis[vt[e]]==vs) continue;int o=dinic(vt[e],min(f-rs,w[e]),cost+v[e]);w[e]-=o; w[e^1]+=o; rs+=o;if(rs==f) return rs;} return dis[x]=-INF,rs;
}
inline int mincostflow() {while(spfa()) {++vs,memcpy(cur+1,g+1,sizeof(int)*des);while(dinic(src,INF,0))++vs,memcpy(cur+1,g+1,sizeof(int)*des);} return ans;
}
int main() {n=rd(),per=rd(),fs=rd(),fsv=rd(),sl=rd(),slv=rd();src=2*n+1; des=src+1;for(int i=1;i<=n;i++) a[i]=rd();for(int i=1;i<=n;i++) add(src,i,a[i],0);for(int i=1;i<=n;i++) add(i+n,des,a[i],0);for(int i=1;i<=n;i++) add(src,i+n,INF,per);for(int i=1;i<n;i++) add(i,i+1,INF,0);for(int i=1;i<n;i++) {if(i+sl<=n) add(i,i+sl+n,INF,slv);if(i+fs<=n) add(i,i+fs+n,INF,fsv);} printf("%lld\n",mincostflow());
}