https://vjudge.net/contest/174235#problem/D
【题意】
- 给定n个已知size的帆布,要给这n块帆布涂上不同的颜色,规则是这样的:
- 每次选择一种颜色C
- 对于颜色为C的所有帆布都要涂上颜色,其中前F个涂为颜色X,剩下的涂为颜色Y,X和Y都是不同于任何已知颜色的颜色
- 每次涂颜色用掉的墨水用量都是帆布的size
- 重复步骤2和3直到所有的帆布都是不同的颜色
- 求最少要多少墨水
【思路】
- 第一次涂把帆布变成两种颜色,剩下每次涂色都是增加一种颜色,所以n块帆布一定是涂n-1次色
- 观察涂色的过程像是一棵树不断分枝
- 可以考虑涂色的逆过程,最初是n种不同的颜色,每次选择两种颜色合并成一种颜色
- 一定是选择size最小的两种颜色合并成一种颜色
- 类似于哈夫曼树,用优先级队列做
【Accepted】
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<set> #include<functional> #include<queue> using namespace std; typedef long long ll; int n; const int maxn=1e5+3; struct node { ll val; friend bool operator<(node n1,node n2) { return n2.val<n1.val; } }a[maxn]; priority_queue<node> q; int main() { int T; scanf("%d",&T); while(T--) { while(!q.empty()) q.pop(); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%lld",&a[i].val); q.push(a[i]); } ll ans=0ll; for(int i=0;i<n-1;i++) { ll x=q.top().val; q.pop(); ll y=q.top().val; q.pop(); ans+=x+y; node nd; nd.val=x+y; q.push(nd); } cout<<ans<<endl; } return 0; }
【优先级队列的用法】
优先级队列的默认排序是从大到小,而且不能重载>,有一下两种方式实现从小到大排序:
1 struct node 2 { 3 ll val; 4 friend bool operator<(node n1,node n2) 5 { 6 return n2.val<n1.val; 7 } 8 }a[maxn];
1 priority_queue<ll,vector<ll>,greater<ll> > q;
【教训】
一开始WA了一发是因为多组数据,没有在每组数据前清空队列,以后对于vector,set,q,pq之类的一定要记得清空