题意:拆分纸牌
题解:这是一道直线拆分的题,可以从左往右做,如果此时这个数小于平均数,那么此时此位这个数必须要从后面来添数进行弥补,设此位位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;
}