卧薪尝胆,厚积薄发。
POI2007 ODW-Weights
Date: Wed Oct 17 13:22:41 CST 2018 In Category: NoCategory

Description:

给一堆砝码,任意两个都存在一个是另一个的整数倍,给一堆箱子,每个有最大承重,问最多能放几个砝码。
$1\leqslant n\leqslant 10^5$

Solution:

首先既然一个是另一个整数倍,那么说明可以贪心,因为把大的分解了可以拼小的,但是直接贪心复杂度过不了,所以先把所有箱子按进制分解,然后把他们分别都丢到一个大根堆里,在同时维护一个大根堆 $rem$ ,表示当前选出了哪些,这个用来后悔,每次从两个堆中各取出来一个,如果相同,那么答案 $+1$ 丢到 $rem$ 里,如果箱子大,那么把箱子容积减掉砝码质量,再放回堆里,如果小的话,那么很不好做,可以从 $rem$ 里拿出来一个拆掉,因为反正一的贡献,由于排序了,要拆的肯定大,拆开能获得更多,所以与其该放弃这个,不如放弃之前的一个还能多获得一些空间,注意一些细节就行了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
inline int read()
{
register int res = 0,f = 1;
register char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
int n,m;
#define MAXN 100010
int w[MAXN],v[MAXN];
int main()
{
scanf("%d%d",&n,&m);
priority_queue<int> q;
for(int i = 1;i <= n;++i)scanf("%d",&w[i]);
for(int i = 1;i <= m;++i)q.push(v[i] = read());
sort(v + 1,v + 1 + m);
m = unique(v + 1,v + 1 + m) - v - 1;
priority_queue<int> s;
for(int i = 1;i <= n;++i)
{
for(int j = m;j >= 1;--j)
{
while(w[i] >= v[j])
{
w[i] -= v[j];
s.push(v[j]);
}
}
}
priority_queue<int> rem;
int ans = 0;
while(!q.empty())
{
int k = q.top();q.pop();//cout << k << endl;
int v;
if(s.empty())v = 0;
else{v = s.top();s.pop();}
if(v == k)
{
++ans;
rem.push(k);
}
else if(v > k)
{
++ans;
rem.push(k);
int r = v - k;
s.push(r);
}
else
{
s.push(v);
if(rem.empty())continue;
else
{
int g = rem.top();rem.pop();
rem.push(k);
int r = g - k;
s.push(r);
}
}
}
cout << ans << endl;
return 0;
}
In tag: 算法-贪心
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡