均分纸牌有三种情况:线性,环形,二维
@[toc]
线性
题目描述
P1031 均分纸牌
有N堆纸牌,编号分别为1,2,…,N。每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。
移动规则:只能向相邻的纸牌移动
问最少移动多少次可以使纸牌数一样多
思路:
第一堆只能给第二堆多干张,或者第二堆给第一堆,这取决于第一堆的初始牌量。当确定第一堆状态后,我们就不用再考虑他,第二堆就变成新的第一堆。
所以我们先求平均值(也就是最终每堆多少张),然后从第一堆开始往后一次比较,如果相等就跳过,如果不是,移动次数就加1
比如:1 1 1 9
平均值为3
第四堆多6张,全部移动到第三堆,然后第三堆再移动四张到第二堆,第二堆再移动两张到第一堆。一共三步
代码:
#include<iostream> using namespace std; int a[10002]; //int jozky() //{ //} int main() { int n,ave=0,sum=0; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; ave=ave+a[i]; } ave=ave/n; for(int i=1;i<=n;i++) { a[i]=a[i]-ave;//与平均值的距离 } for(int i=1;i<=n;i++) { if(a[i] == 0) continue; sum++; a[i+1] = a[i]+a[i+1];//a是前缀和(表示前i堆与平均值的距离情况) } cout<<sum<<endl; return 0; }
环形
题目描述
我们将上一个问题由线性改成环形,也就是第一位和最后一位是相邻的,他们之间也可以互相给牌,这样任意一位都有两个临点
问最少代价是多少?挪动一张牌的代价是1
(上一个题是问最少移动多少次)
思路
既然是环形,我们完全可以拆环成链,然后用上面那个题的方式来解决
橙色圈住的部分我们都可以看做坐标上的点,那xn的绝对值我们就可以看做点x与橙色部分的距离,然后求最短距离和
如果有偶数个点,就是最中间两个点的平均
如果是奇数,就是最中间的点
橙色部分每个点之间的距离都是有规律的,代码里有
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n; const int maxn=1e6+4; ll a[maxn]; int main() { cin>>n; ll sum=0; for(int i=1;i<=n;i++) { cin>>a[i]; sum+=a[i]; } sum/=n; for(int i=n;i>1;i--) { a[i]=sum-a[i]+a[i+1];//为啥是这个公式可以在我那个推到里面得到 } a[1]=0; sort(a+1,a+n+1); ll res=0; int mid=(n+1)/2; for(int i=1;i<=n;i++) { res+=abs(a[i]-a[mid]); } cout<<res<<endl; return 0; }