看到那么多大佬都开坑刷题,那我也随波逐流一下。。。虽然保不准什么时候就弃掉了。。
进度:
8/24
1、餐巾计划问题(费用流)
题目传送门:https://www.luogu.org/problemnew/show/P1251
这道题还是比较思维的。。。(然而说白了都是套路)
显然我们可以把餐巾使用量看作网络的流量,把花费看作网络的费用。
这道题主要的难点就在于如何保证每天一定有ai条餐巾用,以及处理干净餐巾的来源与脏餐巾的去向。因为只能通过源汇来控制整个网络的流量(即餐巾的使用量),所以我们可以把使用一条干净餐巾的过程拆成两个部分:(1)把一条干净的餐巾流进汇点;(2)让一条脏餐巾从源点流出。
于是把一天拆成两个点,一个用来接受脏餐巾,一个用来使用干净的餐巾,然后按题意连边(把脏餐巾洗干净),跑最小费用最大流就行了。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<ctime> #include<algorithm> #include<queue> #include<vector> #define ll long long #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #define inf 0x3f3f3f3f #define mod 1000000007 #define eps 1e-18 inline ll read() { ll tmp=0; char c=getchar(),f=1; for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1; for(;'0'<=c&&c<='9';c=getchar())tmp=(tmp<<3)+(tmp<<1)+c-'0'; return tmp*f; } using namespace std; struct edge{ int from,to,nxt; ll w,flow; }e[1600010]; int fir[4010],inq[4010],last[4010]; ll dist[4010]; int q[1600010]; int a[2010]; int n,S,T,tot=0; void add(int x,int y,ll w,ll f) { e[tot].from=x; e[tot].to=y; e[tot].w=w; e[tot].flow=f; e[tot].nxt=fir[x]; fir[x]=tot++; e[tot].from=y; e[tot].to=x; e[tot].w=-w; e[tot].flow=0; e[tot].nxt=fir[y]; fir[y]=tot++; } int spfa() { int h=1,t=1,i; for(i=0;i<=T;i++)dist[i]=inf,inq[i]=0,last[i]=-1; q[1]=S; dist[S]=0; inq[S]=1; while(h<=t){ int now=q[h++]; inq[now]=0; for(i=fir[now];~i;i=e[i].nxt) if(e[i].flow&&dist[e[i].to]>dist[now]+e[i].w){ dist[e[i].to]=dist[now]+e[i].w; last[e[i].to]=i; if(!inq[e[i].to]){ q[++t]=e[i].to; inq[e[i].to]=1; } } } if(dist[T]==inf)return 0;else return 1; } ll flow() { ll ans=inf; for(int i=T;i!=S;i=e[last[i]].from)ans=min(ans,e[last[i]].flow); for(int i=T;i!=S;i=e[last[i]].from) e[last[i]].flow-=ans,e[last[i]^1].flow+=ans; return ans; } int main() { int i; n=read(); S=0; T=2*n+1; for(i=1;i<=n;i++)a[i]=read(); memset(fir,255,sizeof(fir)); ll p0=read(),t1=read(),p1=read(),t2=read(),p2=read(); for(i=1;i<=n;i++){ add(S,i,0,a[i]); add(i+n,T,0,a[i]); if(i+t1<=n)add(i,i+t1+n,p1,inf); if(i+t2<=n)add(i,i+t2+n,p2,inf); add(S,i+n,p0,inf); if(i<n)add(i,i+1,0,inf),add(i+n,i+n+1,0,inf); } ll ans=0; while(spfa())ans+=flow()*dist[T]; printf("%lld\n",ans); }