P2512 [HAOI2008]糖果傳遞&&P3156 [CQOI2011]分金幣&&P4016 負載平衡問題
阿新 • • 發佈:2018-09-01
algorithm -m for href www %d pro ref tdi
P2512 [HAOI2008]糖果傳遞
第一步,當然是把數據減去平均數,然後我們可以得出一串正負不等的數列
我們用sum數組存該數列的前綴和。註意sum[ n ]=0
假設為鏈,那麽可以得出答案為abs( sum[ 1 ] )+abs( sum[ 2 ] )+...+abs( sum[ n ] )
但是題目說的是環
我們設在第 k 個人處斷開環成鏈。 那麽答案為
abs( sum[ k+1 ] - sum[ k ] )+abs( sum[ k+2 ] - sum[ k ] )+...+abs( sum[ n ] - sum[ k ] )+abs( sum[ n ] - sum[ k ] + sum[ 1 ])+abs( sum[ n ] - sum[ k ] + sum[ 2 ])+...+abs( sum[ n ] - sum[ k ] + sum[ k ])
代入sum[ n ]=0
後,得abs( sum[ k+1 ] - sum[ k ] )+abs( sum[ k+2 ] - sum[ k ] )+...+abs( sum[ n ] - sum[ k ] )+abs( sum[ 1 ] - sum[ k ] )+abs( sum[ 2 ] - sum[ k ] )+...+abs( sum[ k ] - sum[ k ] )
=abs( sum[1~n] - sum[k] )
我們把 sum[1~n]
扔到數軸上,發現問題變成:找出一個點,使它到其他點的距離最小。顯然這個點是中位數。
end.
#include<cstdio> #include<cstring> #include<cmath> #include<cctype> #include<algorithm> using namespace std; typedef long long ll; inline ll Get(){ char c=getchar(); ll x=0; while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x; } ll ans,a[1000002],sum[1000002]; int n; int main(){ scanf("%d",&n); ll tot=0; for(int i=1;i<=n;++i) a[i]=Get(),tot+=a[i]; tot/=n; for(int i=1;i<=n;++i) a[i]-=tot,sum[i]=a[i]+sum[i-1]; //減平均數,求前綴和 sort(sum+1,sum+n+1); ll mid=sum[(n+1)>>1]; //排序後找中位數 for(int i=1;i<=n;++i) ans+=abs(sum[i]-mid); printf("%lld",ans); return 0; }
P2512 [HAOI2008]糖果傳遞&&P3156 [CQOI2011]分金幣&&P4016 負載平衡問題