您的位置:首页 > 其它

Codeforces Round #274(Div2) B. Towers 贪心

2015-07-15 14:04 471 查看
解法一:复杂度为O(nk)

每次从最大值向最小值移动1个

代码如下:

#include <cstdio>
using namespace std;
#define N 1005
int a[105], ans
[2];

int main(){
int n, k, ops = 0, max_val, min_val;
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
while(ops <= k){
max_val = 0, min_val = 10005;
int max_idx, min_idx;
for(int i = 1; i <= n; i ++){
if(max_val < a[i])
max_val = a[i], max_idx = i;
if(min_val > a[i])
min_val = a[i], min_idx = i;
}
if(max_val - min_val < 2 || ops == k)
break;
ans[ops][0] = max_idx, ans[ops][1] = min_idx;
a[max_idx] --, a[min_idx] ++;
ops ++;
}
printf("%d %d\n", max_val - min_val, ops);
for(int i = 0; i < ops; i ++)
printf("%d %d\n", ans[i][0], ans[i][1]);
return 0;
}


本题中n范围较小,所以O(nk)的复杂度没问题

解法二:复杂度为O(nlogn)

思路:在有序的数组中将最大值向最小值移动1,可以保证数组仍然有序。

首先排一次序,记录每个高度的tower个数。每次从数组的末端区间(最大值处)向前端区间(最小值处)移动1。目的是让max_val减小,min_val增大。整个过程中记录下最大值的起点upper和最小值的起点lower,根据最大值的个数more和最小值的个数less的大小关系讨论。

①当more > less时,说明最大值的tower数目比最小值的tower数目多,则最小值的tower全部可以增加一个高度,新的高度仍为最小值,则lower = 0,min_val增加1;此时只有less个最大tower的高度减小了1,下次应从第upper - less个tower开始减小高度

②当more < less时,说明最小值的tower数目较多,则最大值的tower全部可以减小一个高度,新的高度仍为最大值,则upper = n - 1,max_val减小1;此时只有more个最小tower的高度增加了1,下次应从第lower + more个tower开始增加高度

③当more = less时,说明每一个最大值的tower都有一个最小值的tower可以移动过去,从而max_val和min_val向理想的方向靠近,lower和upper都回到数组的首尾两端

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 10005
struct Node{
int val, idx;
friend bool operator< (const Node& a, const Node& b){
return a.val < b.val;
}
}towers[105];
int cnt
, ans[1005][2], ops = 0, k;

void fill(int fill_cnt, int upper, int lower){   //从最大值向最小值移动1
int j = 0;
while(j < fill_cnt && ops < k){
ans[ops][0] = towers[upper - j].idx, ans[ops][1] = towers[lower + j].idx;
ops ++, j ++;
}
}

int main(){
int n;
scanf("%d %d", &n, &k);
for(int i = 0; i < n; ++i){
int x;
scanf("%d", &x), cnt[x] ++;
towers[i].val = x, towers[i].idx = i + 1;
}
sort(towers, towers + n);
int max_val = towers[n - 1].val, min_val = towers[0].val;
int upper = n - 1, lower = 0;
while(ops < k && max_val - min_val > 1){   //最大值和最小值隔1时,最优解已无法减小
int more = cnt[max_val], less = cnt[min_val];
if(more > less && ops + less <= k){   //最小的tower都增加了1个高度
fill(less, upper, lower);
cnt[++min_val] += less,  cnt[max_val] -= less, cnt[max_val - 1] += less;
upper -= less, lower = 0;
}
else if(more < less && ops + more <= k){  //最高的tower都减小了1个高度
fill(more, upper, lower);
cnt[--max_val] += more, cnt[min_val] -= more, cnt[min_val + 1] += more;
lower += more, upper = n - 1;
}
else{
if(ops + more <= k)
cnt[--max_val] += more, cnt[++min_val] += less;
fill(more, upper, lower);
upper = n - 1, lower = 0;
}
}
printf("%d %d\n", max_val - min_val, ops);
for(int i = 0; i < ops; i ++){
printf("%d %d\n", ans[i][0], ans[i][1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: