1045 糖果传递
设xi为第i个人向第i+1个人传递的糖果数,那么就有等式:a[i]+x(i-1)-x(i)=ave
即:a[2]+x1-x2=ave -> x2=a[2]+x1-ave=x1-c1
a[3]+x2-x3=ave -> x3=a[3]+x2-ave=x1-c2
c1=ave-a[1];c2=c1+ave-a[2];… cn=c(n-1)+ave-a[n-1] (网上很多代码递推到c(n))
所以传递次数=abs(x1)+abs(x2)+…+abs(xn)
=abs(x1)+abs(x1-c1)+…+abs(x1-c(n-1))
当x1,为0,c1,…,c(n-1)的中位数时,传递次数最小 (网上很多取的是c1...cn的中位数)
我就很纳闷,为什么递推到cn取c1...cn的中位数也能ac
以下为正确思想的ac代码
/**************************************************************
Problem: 1045
User: syh0313
Language: C++
Result: Accepted
Time:2712 ms
Memory:16916 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=1000010;
int n;
long long a[maxn],sum,ave,now,ans,b[maxn];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
ave=sum/(long long)n;
for (int i=2;i<=n;i++) b[i]=b[i-1]+a[i]-ave;
sort(b+1,b+n+1);
int now=b[n/2];
for (int i=1;i<=n;i++) ans+=abs(now-b[i]);
printf("%lld\n",ans);
return 0;
}
以下为递推到cn取c1...cn的中位数的ac代码(网上这种居多,但是思想是不对的)
/**************************************************************
Problem: 1045
User: syh0313
Language: C++
Result: Accepted
Time:2744 ms
Memory:16916 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=1000010;
int n;
long long a[maxn],sum,ave,now,ans,b[maxn];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
ave=sum/(long long)n;
for (int i=1;i<=n;i++) b[i]=b[i-1]+a[i]-ave;
sort(b+1,b+n+1);
int now=b[n/2];
for (int i=1;i<=n;i++) ans+=abs(now-b[i]);
printf("%lld\n",ans);
return 0;
}
本文详细解析了1045糖果传递问题的算法思路,通过建立数学模型,利用中位数优化糖果传递次数,提供了两种AC代码实现方式,并对比了其背后的逻辑差异。
1万+

被折叠的 条评论
为什么被折叠?



