zoukankan      html  css  js  c++  java
  • 【BZOJ1045】糖果传递(基于贪心的数学题)

    点此看题面

    大致题意:(n)个小朋友坐成一圈,每人有(a[i])个糖果。每人只能给左右两人传递糖果,传递一个糖果代价为1,求使所有人获得均等糖果的最小代价。

    数学转换

    这题其实是一道带有浓厚数学色彩的贪心题。

    我们可以先用(sum)来统计(a[i])之和,然后将(sum)除以(n),从而求出最后每个小朋友应该拥有的糖果的个数。

    我们可以用(s[i])来表示第(i)个人给第(i+1)个人的糖果数量(如果为负,表示第(i+1)个人给第(i)个人(-s[i])颗糖果),特殊的,(s[n])表示第(n)个人给第(1)个人的糖果数量。

    我们可以发现,对于第(i)个人,他的手上拿着的糖果数应为(a[i]+s[i-1]),即他原本拥有的糖果和第(i-1)个人给他的糖果,又由于每个人应拿的糖果数为(sum),所以(a[i]+s[i-1]-sum)即为他要交给第(i+1)个人的糖果数。
    (s[i]=a[i]+s[i-1]-sum)

    那么$$ans=sum_{i=1}^n |s[i]-S|$$

    其中,(S)为一个定值。而我们的目的就是取一个合适的(S)使(ans)最小。

    如何求解

    那么,这道题目就变成了一个我们很熟悉的一个经典数学问题了,我们可以将(s[1]sim s[n])一一对应到数轴上,不难发现,最优的(S)应为(s)数组的中位数

    这样一来,这题就很简单了。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) (x>y?x:y)
    #define min(x,y) (x<y?x:y)
    #define LL long long
    #define N 1000000
    using namespace std;
    int n,a[N+5],s[N+5];
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if(ch=='-') f=-1,ch=getchar();
    	while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar();
    	return x*=f;
    }
    void write(LL x)
    {
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10+'0');
    }
    int main()
    {
    	n=read();
    	LL sum=0;
    	for(int i=1;i<=n;i++) sum+=(a[i]=read());//用sum计算出总糖果数
    	sum/=n;//将sum除以n,得出每个人应拿的糖果数
    	for(int i=1;i<=n;i++) s[i]=a[i]+s[i-1]-sum;//递推求出s[]数组
    	sort(s+1,s+n+1);//排序一遍,找出中位数
    	LL ans=0;//ans统计答案
    	for(int i=1;i<=n;i++) ans+=abs(s[i]-s[(n+1)>>1]);//求出Σ|s[i]-S|,其中S为s[]数组的中位数,即s[(n+1)>>1]
    	return write(ans),0;
    }
    
  • 相关阅读:
    flutter canvas 简单绘画直线
    Yapi 部署及遇到的坑
    flutter 时间选择器第三方插件返回时间格式说明
    windows + flutter + vscode 连接其他模拟器
    flutter 配置环境
    flutter 返回键监听
    flutter 自定义主题切换
    flutter Provide 状态管理篇
    flutter 本地存储 (shared_preferences)
    JS做倒计时的例题
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1045.html
Copyright © 2011-2022 走看看