HDU 6438 Buy and Resell CCPC网络赛(贪心)

HDU 6438 Buy and Resell CCPC网络赛(贪心)

 

题意 : 给出一些数、你可以从左到右对这些数进行三种操作花费 Ai 买入东西、以 Ai 价格卖出你当前有的东西、或者什么都不做、现在问你可以获取的最大利益是多少?

 

分析:和CF 867E差不多

对于每个元素产生的贡献

可以先算出暂时的最优值

如果下次碰到更优的选择再进行替换

具体就是首先使用小顶堆维护枚举过的元素

然后对于当前枚举到的元素

用它和堆顶元素做对比、如果小于或等于堆顶元素

那么它无法和之前枚举过的所有元素的任何一个做减法产生贡献

所以将其加入这个小顶堆当中去

如果大于堆顶元素、则用它和堆顶元素做减法、算出它和堆顶元素产生贡献

当然这个贡献只是暂时最优的、堆顶元素和当前枚举到的元素进行配对并不一定是最优的

那么怎么样在下一次枚举到更优的配对元素时进行替换

答案就是做完贡献之后、将堆顶元素弹出、然后 push 两次当前枚举到的元素进入堆内

第一个 push 的意义是下次如果其作为堆顶元素、那么可以把它拿出来做减法达到反悔操作

第二个 push 的意义是下次拿出来的话就是真正的卖出去

 

 

代码:

#include

using namespace std;

 

const double EPS = 1e-6;

const int INF = 0x3f3f3f3f;

const int mod = 1e9 + 7;

const int maxn = 1e5 + 10;

int n;

int a[maxn];

priority_queue, greater > Q;

map mp;

 

int main()

{

    int T;

    scanf("%d", &T);

    while(T--){

        scanf("%d", &n);

        for(int i = 0; i < n; i++) scanf("%d", &a[i]);

 

        while(!Q.empty()) Q.pop(); mp.clear();

 

        long long ans = 0, cnt = 0;

        for(int i = 0; i < n; i++){

            if(!Q.empty() && Q.top() < a[i]){

                int x = Q.top(); Q.pop();

                ans += a[i] - x; cnt++;

 

                if(mp[x]){ mp[x]--; cnt--;}

 

                Q.push(a[i]); mp[a[i]]++;

            }

            Q.push(a[i]);

        }

 

        printf("%lld %lld\n", ans, cnt << 1);

    }

 

    return 0;

}

 

你可能感兴趣的:(贪心,优先队列)