P1031 均分纸牌(直线拆分)->[HAOI2008] 糖果传递(环形拆分)(数学)

题意:拆分纸牌

题解:这是一道直线拆分的题,可以从左往右做,如果此时这个数小于平均数,那么此时此位这个数必须要从后面来添数进行弥补,设此位位i,则a[i+1]-=(ave-a[i]),如果此为大于平均数,那么就得向右边传数,a[i+1]+=(a[i]-ave),如果此位为0,那么直接跳过即可,这样这个题确实可以求出来,并且思维难度不大,对于后面这道题会有点启示。

附上代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn=1e2+50;

int n,a[maxn],sum,ave;

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    ave=sum/n;
    int cnt=0;
    for(int i=0;i<n-1;i++){
        if(a[i]>ave){
            cnt++;
            a[i+1]+=(a[i]-ave);
        }else if(a[i]<ave){
            cnt++;
            a[i+1]-=(ave-a[i]);
        }else if(a[i]==ave){
            continue;
        }
    }
    printf("%d\n",cnt);
    return 0;
}

题意:糖果传递

题解:这道题变成了环形传递,并且需要算出传递的最小数量,其实根据上面我们就稍微有点提示了, 可以设x[i]为第i+1位向第i位传输的数量,如果为正,说明是从第i+1传向第i位的,如果是负的,说明是从第i位向第i+1传了,所以此时可以列出一系列方程了:

a1-xn+x1=ave

a2-x1+x2=ave

a3-x2+x3=ave

an-x(n-1)+xn=ave(a本式子可以通过前面n-1个式子推出来,所以其实无用)

然后重新排下,把所有的x[i]都表示成x1表示出来的形式

xn=x1-(ave-a1)

x2=x1-(a2-ave)

x3=x2-(a3-ave)

x1=x1-0

最后想要|x1|+|x2|+|x3|+……+|x[n]|最小,然后可以设c数组为ai-ave,之后再进行表示就是:

xn=x1-(-c1)

x2=x1-c2

x3=x2-c3

x1=x1-0

然后绝对值相加起来就是|x1|+|x1-c2|+|x1-(c2+c3)|+|x1-(c2+c3+c4)|+……+|x1-(-cn)|的值,然后可以看出来的是这就是给出了数轴上一些定点,让你求出数轴上某个点到这些点的距离之和最小,然后输出距离之和,其实这个点也就是这些数的中位数,证明见传送门

附上代码:

#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
 
const int maxn=1e6+5;
 
ll n,a[maxn],c[maxn],sum,ave,sta,ans;
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    ave=sum/n;
 
    for(int i=1;i<=n;i++){
        c[i]=a[i]-ave;
    }
    c[1]=-c[1];
    for(int i=3;i<=n-1;i++){
        c[i]=c[i]+c[i-1];
    }
    c[n]=0;
    sort(c+1,c+n+1);
    sta=n/2+1;
    for(int i=1;i<=n;i++){
        ans+=abs(c[i]-c[sta]);
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/85870879