题目链接:
http://codevs.cn/problem/1098/
题意:
有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。
移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
分析:
首先明确顺序随意且纸牌的移动顺序并不影响最终的移动次数。
那么我们假设按照由左而右的顺序移动。
首先考虑第一张纸牌,如果数量不满足平均,那么后续必有一个步骤是移走他多余的纸牌的,所以肯定是把他所有多余纸牌一次性拿走是最优的,同理若不足平均值,则用他右边的纸牌数来一次性补充满足,那么现在问题来了,如果右边的纸牌数不够移给他左边的怎么办。。我们在移动过程中,只是改变了移动的顺序,而移动的次数不变,后面肯定会有一个步骤使得右边的纸牌数增加,那么我们让这个步骤先行即可。
贪心的关键是,减少操作数一次性让纸牌满足条件,顺序不会影响答案,出现负数的情况也继续操作。
代码:
/*
On a hill is a tree, on a tree is a bough;
My heart for the Lord, but he never knows.
--Created by jiangyuzhu
--2016/5/17
*/
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<stack>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<cmath>
using namespace std;
#define pr(x) cout << #x << ": " << x << " "
#define pl(x) cout << #x << ": " << x << endl;
#define sa(x) scanf("%d",&(x))
#define sal(x) scanf("%I64d",&(x))
#define mdzz cout<<"mdzz"<<endl;
typedef long long ll;
const int maxn = 1e2 + 5, mod = 1e9 + 7;
int a[maxn];
int main(void)
{
int n;sa(n);
int tot = 0;
for(int i = 0; i < n; i++){
sa(a[i]);
tot += a[i];
}
tot /= n;
int ans = 0;
for(int i = 0; i < n; i++){
if(a[i] == tot) continue;
if(a[i] < tot) a[i + 1] -= tot - a[i];
if(a[i] > tot) a[i + 1] += a[i] - tot;
ans++;
}
printf("%d\n", ans);
return 0;
}
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1045
题意:
有
n
个小朋友坐成一圈,每人有
分析:
证明摘自:http://hzwer.com/2656.html
我们用
xi
表示第
i
个小朋友给第
我们假设最后每个人剩
avg
个糖果,那么可以得到:
对于第一个小朋友:
a1+x2−x1=avg
对于第二个小朋友:
a2+x3−x2=avg
…
对于最后一个小朋友:
an+x1−xn=avg
整理一下即可得到:
x2=avg−a1+x1
x3=avg−a2+x2=2avg+x1−a2−a1
…
xn=avg−an−1+xn−1=(n−1)avg+x1−∑n−1i=1ai
我们令
ci=∑ij=1ai+i×avg
,上述式子即可转化为求解
|x1|+|x1−c1|+|x1−c2|...+|x1−cn−1|
的最小值,那么直接令
x1
等于
c
<script type="math/tex" id="MathJax-Element-526">c</script>的中位数即可。
代码:
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<stack>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<cmath>
using namespace std;
#define pr(x) cout << #x << ": " << x << " "
#define pl(x) cout << #x << ": " << x << endl;
#define sa(x) scanf("%d",&(x))
#define sal(x) scanf("%lld",&(x))
#define mdzz cout<<"mdzz"<<endl;
typedef long long ll;
const int maxn = 1e6 + 5, mod = 1e9 + 7;
ll a[maxn], c[maxn];
int main(void)
{
int n;sa(n);
ll tot = 0;
for(int i = 0; i < n; i++){
sal(a[i]);
tot += a[i];
}
tot /= n;
ll ans = 0;
for(int i = 0; i < n; i++)
c[i] = c[i - 1] + a[i] - tot;
sort(c, c + n);
int t = c[n / 2];
for(int i = 0; i < n; i++){
ans += abs(c[i] - t);
}
printf("%lld", ans);
return 0;
}