GYM 101128 C.Canvas Painting【思维+优先队列】

来源:互联网 发布:c语言字符串指针传递 编辑:程序博客网 时间:2024/05/17 23:51



题目大意:


有N个物品,每个物品价值为Ai,现在我们可以任意打乱这些物品的位子,使得位子固定之后,初始每个物品的颜色都是白色,然后我们每一次操作可以选择一个颜色的区间,使得涂抹任意长度的部分,剩余的该颜色的部分会被涂抹成另外新的颜色,每一次涂抹的需要的花费是整个颜色的价值和。

问如何摆放并且涂抹会使得所有最终的物品的颜色都不同,并且花费最小。


思路:


反向考虑,假设我们一开始颜色都不同,那么问题就变成了,每一次选择两个颜色的物品,将其合并,变成一种颜色的物品。

那么问题其实就是在求,两两合并最终合并成一个的过程的总和最小值,如果不能改变物品的位子的话,那么这个数据量显然是一个NP难的问题(如果数据量小就是我们熟知的区间Dp),但是这个题允许位子改变,所以我们只要有贪心合并的过程,按此排列即可。每次取出最小价值的两个颜色,将其合并成一个颜色,统计过程中的花费总和就行了。贪心求出最小值。


Ac代码:

#include<stdio.h>#include<string.h>#include<queue>using namespace std;#define ll __int64int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n;        scanf("%d",&n);        priority_queue<ll, vector<ll>, greater<ll> >s;        for(int i=1;i<=n;i++)        {            ll x;            scanf("%I64d",&x);            s.push(x);        }        ll ans=0;        while(!s.empty())        {            if(s.size()==1)break;            else            {                ll u=s.top();s.pop();                ll v=s.top();s.pop();                ll w=u+v;ans+=w;                s.push(w);            }        }        printf("%I64d\n",ans);    }}