【贪心】均分纸牌问题

环形均分纸牌

均分纸牌noip2002   

N堆纸牌,每堆上有若干张,纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。

移牌规则:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的纸牌,只能移到编号为N1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多

第一堆牌相差的牌只能由第二堆牌承担(给予或索要)

一堆一堆处理 只考虑后一堆(前一堆已经处理好 再处理它会造成浪费

#include<bits/stdc++.h>
using namespace std;
#define rg register
const int N=1e6+5,M=1e6+5,inf=0x3f3f3f3f,P=9999973;
int n,a[N],x=0,ans=0;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int main(){
    rd(n);
    for(int i=1;i<=n;++i) rd(a[i]),x+=a[i];
    x/=n;
    for(int i=1;i<=n;++i)
    if(a[i]-x) ++ans,a[i+1]+=(a[i]-x);
    printf("%d",ans);
    return 0;
}

[HAOI2008]糖果传递

有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。求使所有人获得均等糖果的最小代价。

假设标号为i的小朋友开始有Ai颗糖果,Xi表示第i个小朋友给了第i-1个小朋友Xi颗糖果,如果Xi<0,说明第i-1个小朋友给了第i个小朋友Xi颗糖果,X1表示第一个小朋友给第n个小朋友的糖果数量。 所以最后的答案就是ans=|X1| + |X2| + |X3| + ……+ |Xn|。 对于第一个小朋友,他给了第n个小朋友X1颗糖果,还剩A1-X1颗糖果;但因为第2个小朋友给了他X2颗糖果,所以最后还剩A1-X1+X2颗糖果。根据题意,最后的糖果数量等于ave,即得到了一个方程:A1-X1+X2=ave。

对于第1个小朋友,A1-X1+X2=ave -> X2=ave-A1+X1 = X1-C1(假设C1=A1-ave,下面类似)

对于第2个小朋友,A2-X2+X3=ave -> X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2

对于第3个小朋友,A3-X3+X4=ave -> X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3

…… 对于第n个小朋友,An-Xn+X1=ave

希望Xi的绝对值之和尽量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要尽量小,注意到|X1-Ci|的几何意义是数轴上的点X1到Ci的距离,所以问题变成了:给定数轴上的n个点,找出一个到他们的距离之和尽量小的点,而这个点就是这些数中的中位数  (from 洛谷第一篇题解

大概可以手推一遍就懂辽

#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) (x)<(y)?(y):(x)
#define Min(x,y) (x)<(y)?(x):(y)
#define ll long long
#define Abs(x) (x)<0?-x:x;
#define rg register
const int N=1e6+5,M=1e6+5,inf=0x3f3f3f3f,P=9999973;
int n;
ll ans=0,a[N],sum[N],b[N],ave=0;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int main(){
//    freopen("in.txt","r",stdin);
    rd(n);
    for(int i=1;i<=n;++i) rd(a[i]),sum[i]=sum[i-1]+a[i];
    ave=sum[n]/n;
    for(int i=1;i<=n;++i) b[i]=b[i-1]-a[i]+ave;
    sort(b+1,b+n+1);
    ll mid;
    if(n%2) mid=b[n+1>>1];
    else mid=(b[n>>1]+b[n>>1|1])/2;
    for(int i=1;i<=n;++i) ans+=abs(mid-b[i]);
    printf("%lld",ans); 
    return 0;
}
原文地址:https://www.cnblogs.com/lxyyyy/p/11285684.html