Codeforces 721D Maxim and Array

预习功课

我通过这个题接触到了stl中的heap。
以前都是用set啊啥的,然而如果你把n个元素全都插入到set里复杂度是相当的高的。
这个时候heap就产生了,而且heap有一个好,它的内部不是有序的,要求没有那么严格,所以这个时候我们就要用heap了。

heap的使用

假设我们定义了一个vector <int> s;

头文件

#include <algorithm>

make_heap

make_heap(s.begin(), s.end());
有时根据自己的需要,可以加入自定义cmp函数。
加cmp的写法是:make_heap(s.begin(), s.end(), cmp);
未加声明时默认是大根堆

pop_heap

pop_heap(s.begin(), s.end());
这个函数并不是真的删掉了最大的元素,而是将最大的元素与原来的最后一项交换,再维护前s.size()-1个元素的性质。

push_heap

push_heap(s.begin(), s.end());
跟pop_heap很相似,是将新的元素加在s的末尾之后重新维护堆的性质。

sort_heap

sort_heap(s.begin(), s.end());
就是对这个堆进行排序,排序之后它就不再是一个堆了,而是一个完全有序的容器。

Example Code
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main () {
  int myints[] = {10, 20, 30, 5, 15};
  vector <int> v(myints, myints+5);

  make_heap(v.begin(), v.end());
  cout << "initial max heap   : " << v.front() << endl;

  pop_heap(v.begin(),v.end()); v.pop_back();
  cout << "max heap after pop : " << v.front() << endl;

  v.push_back(99); push_heap (v.begin(), v.end());
  cout << "max heap after push: " << v.front() << endl;

  sort_heap (v.begin(), v.end());

  cout << "final sorted range :";
  for (unsigned i=0; i < v.size(); i++) cout << " " << v[i];

  cout << endl;

  return 0;
}

输出结果:

initial max heap   : 30
max heap after pop : 20
max heap after push: 99
final sorted range : 5 10 15 20 99
当然

我们其实不一定要用vector,数组也是可以的,只要函数里的两个位置是开头和结尾的指针就行。
比如我们定义了一个:int a[6] = {3, 5, 2, 1, 4};
那么调用make_heap只需make_heap(a, a+5);就行。

进入正题

题意

给你n,k,x以及n个数a1,a2,...,an每次操作你可以对ai进行+x或者-x,总共k次,且这些操作需最小化$$prod_{i=1}^{n} a_i$$ 问k次操作之后每个元素各是多少。

想法

首先肯定要分类讨论一下。令$$s = prod_{i=1}^{n} a_i$$如果s是正的,那么我们一定会想减小绝对值最小的那个数的绝对值,最好能让s变负数,如果s本身就是负数,那么我们只需考虑所有数的绝对值,然后让绝对值最小的那个数的绝对值增大(为什么是绝对值最小的而不是最大的你做个商就好了)。每次操作都是对绝对值最小的那个数进行操作,显然这就需要用到堆了。

Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long 
#define db double
#define N 200010
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define swap(T, a, b) ({T ttt = a; a = b; b = ttt;})
using namespace std;

#define Sig(x) (x < 0 ? -1 : 1)

ll a[N], b[N], x; 
int n, k, sig = 1; 
bool cmp(int x, int y) { return abs(a[x]) > abs(a[y]); } 

int main()
{
   scanf("%d%d%I64d", &n, &k, &x); 
   for (int i = 1; i <= n; i++)
      scanf("%I64d", &a[i]), sig *= Sig(a[i]), b[i] = i;
   make_heap(b+1, b+n+1, cmp); 
   while (k--) {
        int t = sig * Sig(a[b[1]]); 
        a[b[1]] -= t * x;
        sig = t * Sig(a[b[1]]); 
        pop_heap(b+1, b+n+1, cmp); 
        push_heap(b+1, b+n+1, cmp); 
    }
    for (int i = 1; i <= n; i++)
        printf("%I64d ", a[i]); 
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值