bzoj 1045 [HAOI2008] 糖果传递——设变量推式子
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1045
费用流TLE。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const int N=1e6+5; const ll INF=1e15; int n,a[N],hd[N],xnt=1,pre[N],dis[N]; ll ans,base; bool vis[N]; struct Ed{ int nxt,to,w; ll cap; Ed(int n=0,int t=0,ll c=0,int w=0):nxt(n),to(t),cap(c),w(w) {} }ed[N<<4]; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar(); return ret; } void add(int x,int y,ll cap) { int k=1;if(!x||y==n+1)k=0; ed[++xnt]=Ed(hd[x],y,cap,k);hd[x]=xnt; ed[++xnt]=Ed(hd[y],x,0,-k);hd[y]=xnt; } queue<int> q; bool spfa() { q.push(0);vis[0]=1; memset(dis,0x3f,sizeof dis);dis[0]=0; while(q.size()) { int k=q.front();q.pop();vis[k]=0; for(int i=hd[k],v;i;i=ed[i].nxt) if(ed[i].cap&&dis[v=ed[i].to]>dis[k]+ed[i].w) { dis[v]=dis[k]+ed[i].w; pre[v]=i; if(!vis[v])vis[v]=1,q.push(v); } } return dis[n+1]<0x3f3f3f3f; } void ek() { ll flow=INF; for(int i=n+1;i;i=ed[pre[i]^1].to) flow=min(flow,ed[pre[i]].cap); for(int i=n+1;i;i=ed[pre[i]^1].to) ed[pre[i]].cap-=flow,ed[pre[i]^1].cap+=flow; ans+=flow*dis[n+1]; } int main() { n=rdn(); for(int i=1;i<=n;i++)a[i]=rdn(),base+=a[i]; base/=n; for(int i=1;i<=n;i++) { if(a[i]>base)add(0,i,a[i]-base); if(a[i]<base)add(i,n+1,base-a[i]); add(i,i-1?i-1:n,INF);add(i,i+1<=n?i+1:1,INF); } while(spfa())ek(); printf("%lld\n",ans); return 0; }
为了计算出每个人传递出去的糖果数量,需要先把它们设出来。
不妨指定一个方向。
然后尽量把每个变量用常量表示出来。
希望自己以后也能想出来。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=1e6+5; int n; ll a[N],base,c[N],ans; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),base+=a[i]; base/=n; for(int i=1;i<n;i++)c[i]=c[i-1]+a[i]-base; sort(c+1,c+n); ll x=c[(n+1)>>1]; for(int i=0;i<n;i++)ans+=abs(x-c[i]); printf("%lld\n",ans); return 0; }