糖果传递与七夕祭

52 篇文章 1 订阅
34 篇文章 0 订阅
本文介绍了如何将糖果传递问题和矩阵调整技巧应用于数据分布不均的场景,通过递推求解和中位数思想优化分配策略,解决ACwing122和ACwing105中的问题。展示了在不同维度(行、列或整体)平衡数量的方法,适用于平均分配与动态调整的难题。
摘要由CSDN通过智能技术生成

今天学了一个新的知识:
ACwing122:糖果传递
在这里插入图片描述
题解:
在这里插入图片描述
如图,a1给an的糖果数目设为x1,a2给a1的糖果数目设为x2.已知最后每个人得到的糖果数目一样设为(avg).那么可以知道对于a1来说有方程->a1-x1+x2=avg.对于a2来说有方程->a2-x2+x3=avg…以此类推.
我们可以把
a1-x1+x2=avg转化成x1-x2=a1-avg.
a2-x2+x3=avg转化为x2-x3=a2-zvg.


x1-x2=a1-avg.
x2-x3=a2-avg.

xn-2-xn-1=an-2-avg.
xn-1-xn=an-1-avg.(1) //这里表示为(1)式方便后面的查找
xn-x1=an-avg.
那么
xn=x1-(avg-an).(2)
xn-1=xn+an-1-avg(1)//由(1)式转化而来,上面也是如此,把(2)式带入xn=x1-(avg-an)+an-1+avg=x1-(2avg-an-an-1)).
易知:
要求的x1+x2+x3+…xn的值要最小.
那么即求
xn=|x1-(avg-an)|
xn-1=|x1-(2
avg-an-an-1))|

x1=|x1-0|的值最小.
不难看出就是要让|x1-dis|值最小,易知此时若x1为所有dis值里面的中位数时|x1-dis|的值最小.
那么先求出所有的dis用一个数组c存储,再排序,其中c[(n+1)/2]就是中位数也就是x1的值.
不难看出dis的值符合递推式c[i]=c[i+1]+avg-a[i].
AC代码如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[1000005],c[1000005];
ll n,sum,avg;

ll func(){
    avg=sum/n;
    for(int i=n;i>1;i--){
        c[i]=c[i+1]+avg-a[i];
    }
    c[1]=0;
    ll ans=0;
    sort(c+1,c+1+n);
    
    for(int i=1;i<=n;i++){
        ans+=abs(c[(n+1)/2]-c[i]);
    }
    return ans;
}

int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){scanf("%lld",&a[i]);
    sum+=a[i];
    }
    printf("%lld\n",func());
}

七夕祭ACwing105.
在这里插入图片描述

在这里插入图片描述
不难看出这道题和上面的糖果传递有异曲同工之妙
在这里插入图片描述
例如当n=3,m=2,k=2时,如上图所示,因为k%n!=0那么就说明不能让每行都有一样数目的摊位,k%m==0那么说明可以让每列有相同的摊位.就变成了糖果传递的问题了.
AC代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
#define ll long long
int row[N],col[N];
int c[N];
int k;

ll func(int a[],int n){
    memset(c,0,sizeof(c));
    ll avg=k/n;
    for(int i=n;i>1;i--){
        c[i]=c[i+1]+avg-a[i];
    }
    c[1]=0;
    sort(c+1,c+1+n);
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans+=abs(c[(n+1)/2]-c[i]);
    }
    return ans;
}

int main(){
    int n,m;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<k;i++){
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        row[t1]++;
        col[t2]++;
    }

    if(k%n==0&&k%m==0){
        printf("both %lld\n",func(row,n)+func(col,m));
    }
    else if(k%n==0){
        printf("row %lld\n",func(row,n));
    }
    else if(k%m==0)printf("column %lld\n",func(col,m));
    else printf("impossible\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值