洛谷传送门
LOJ传送门
解析:
这道题其实就是环形的均摊纸牌。
但是你毕竟是来练习网络流的
所以我们来谈一谈怎么建图跑网络流吧。
对于每一个仓库,向相邻两个仓库连容量为INFINFINF,费用为111的边。
建立超级源点SSS,向每一个点连容量为仓库原来库存量的边,费用为0。
建立超级汇点TTT,每个点向汇点连容量为tot/ntot/ntot/n的边,费用为0。
这样跑出来的最小费用最大流就是我们要的答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define pc putchar
#define gc getchar
#define cs const
cs int N=103,M=403,INF=0x3f3f3f3f;
cs int S=0,T=N-1;
int last[N],nxt[M<<1],to[M<<1],ecnt=1;
int cap[M<<1],w[M<<1];
inline void addedge(int u,int v,int val,int cost){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=cost,cap[ecnt]=val;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=-cost,cap[ecnt]=0;
}
bool vis[N];
int dist[N];
int cur[N];
queue<int> q;
inline bool SPFA(){
memset(dist,INF,sizeof dist);
memset(vis,0,sizeof vis);
dist[S]=0;
cur[S]=last[S];
q.push(0);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&dist[v]>dist[u]+w[e]){
dist[v]=dist[u]+w[e];
if(!vis[v])q.push(v),vis[v]=true,cur[v]=last[v];
}
}
}
return dist[T]<INF;
}
int dfs(cs int &u,cs int &flow,int &co){
if(u==T){
co+=flow*dist[T];
return flow;
}
int ans=0;
vis[u]=true;
for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&!vis[v]&&dist[v]==dist[u]+w[e]){
int delta=dfs(v,min(flow-ans,cap[e]),co);
if(delta){
cap[e]-=delta;
cap[e^1]+=delta;
ans+=delta;
if(ans==flow)return flow;
}
}
}
return ans;
}
int MCMF(){
int cost=0,ans=0;
while(SPFA())ans+=dfs(S,INF,cost);
return cost;
}
int n,tot;
signed main(){
scanf("%d",&n);
for(int re i=1;i<=n;++i){
int val;
scanf("%d",&val);
tot+=val;
addedge(S,i,val,0);
addedge(i,i%n+1,INF,1);
addedge(i,(i==1)?n:(i-1),INF,1);
}
for(int re i=1;i<=n;++i)addedge(i,T,tot/n,0);
cout<<MCMF();
return 0;
}