减数游戏

题目链接:nowcoder 214272

到主站看:https://blog.csdn.net/weixin_43346722/article/details/112730284

题目大意

有一个序列,你每次可以把两个数去掉,改成这两个数的乘积加 k。
然后问你变换到最后剩下的数最大可以是多少。

思路

这道题我们考虑贪心,可以看出肯定是选择最小的那两个乘。

那我们考虑用堆维护,但是你会发现乘到后面会有取模,然后就会导致堆里面最小的并不是真正最小的。

那怎么办呢?
那我们会发现,乘到最后,数已经很大了,把最小的两个乘起来,也会比之前最大的还要大。

那我们就考虑先用堆乘到这个情况(就先不取模),然后把身下的用一个队列维护,直接每次把对前面两个去掉变成它们的乘积加

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define mo 1000000007

using namespace std;

queue <int> qq;
int n, k, ans, maxn;
ll x, y;
priority_queue <int, vector<int>, greater<int> > q; 

int main() {
    scanf("%d %d", &n, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &x);
        q.push(x);
        maxn = max(maxn, (int)x);
    }

    while (q.size() > 1) {
        x = q.top();
        q.pop();
        y = q.top();
        q.pop();

        if (x * y + k > maxn) {//最小的两个乘起来比原来最大的还要大了
            q.push(x);
            q.push(y);
            break;
        }

        q.push(x * y + k);
    }

    while (!q.empty()) {
        qq.push(q.top());
        q.pop();
    }

    while (qq.size() > 1) {
        x = qq.front();
        qq.pop();
        y = qq.front();
        qq.pop();

        qq.push(((ll)x * y + k) % mo);
    }

    printf("%d", qq.front()); 

    return 0;
}