-
题目:

-
思路:
贪心策略:
从大到小填m,用vector存每个分组内的元素。优先队列中维护分块内的元素数目(小根堆)。如果当前m可以填入队顶分组内,则一直往当前队顶分组放元素,直至不能再放;如果当前m不可以填入队顶分组内,那么说明需要新建分组,再一直往新的分组内填元素,直至不能填。
算法正确性还是比较显然的。当然也可以不采用可以填就一直填的策略,也可以单个单个的填,但是注意优先队列比较符的重载方式会略有不同。
总的来说每次都应贪心的选择当前元素数目最少的分组,并且要注意优先队列中元素的更新!
时间复杂度O(nlogn)级别 -
ac代码:
方法1:可以填一直填
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
int n, k;
int m[maxn], c[maxn];
vector<int> ans[maxn];
struct Que{
int id;
friend bool operator < (Que a, Que b)
{
return ans[a.id].size()>ans[b.id].size();
}
};
priority_queue<Que> q;
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++) scanf("%d", &m[i]);
sort(m+1, m+1+n, greater<int>());
for(int i = 1; i <= k; i++) scanf("%d", &c[i]);
int cnt = 1;
q.push({1});
for(int i = 1; i <= n; i++)
{
int id = q.top().id;
if(ans[id].size()<c[m[i]])//当前还可填,一直填到不能填
{
while(ans[id].size()<c[m[i]]) ans[id].push_back(m[i]), i++;
i--;
q.pop();
q.push({id});
}
else//增加新的分组,一直填
{
cnt++;
while(ans[cnt].size()<c[m[i]]) ans[cnt].push_back(m[i]), i++;
i--;
q.push({cnt});
}
}
printf("%d\n", cnt);
for(int i = 1; i <= cnt; i++)
{
printf("%d", ans[i].size());
for(auto e : ans[i]) printf(" %d", e);
printf("\n");
}
return 0;
}
方法2:单个单个的填
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
int n, k;
int m[maxn], c[maxn];
vector<int> ans[maxn];
struct Que{
int id, mx;
friend bool operator < (Que a, Que b)
{
//return ans[a.id].size()>ans[b.id].size();
return ans[a.id].size()==ans[b.id].size()?a.mx>b.mx:ans[a.id].size()>ans[b.id].size();
}
};
priority_queue<Que> q;
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++) scanf("%d", &m[i]);
sort(m+1, m+1+n, greater<int>());
for(int i = 1; i <= k; i++) scanf("%d", &c[i]);
int cnt = 1;
q.push({1, 0});
for(int i = 1; i <= n; i++)
{
int id = q.top().id, mx = q.top().mx;
if(ans[id].size()<c[m[i]])
{
ans[id].push_back(m[i]);
q.pop(); q.push({id, mx});//注意此处!
}
else
{
cnt++;
ans[cnt].push_back(m[i]);
q.push({cnt, m[i]});
}
}
printf("%d\n", cnt);
for(int i = 1; i <= cnt; i++)
{
printf("%d", ans[i].size());
for(auto e : ans[i]) printf(" %d", e);
printf("\n");
}
return 0;
}
本文介绍了一种使用贪心策略解决特定分组问题的方法,通过优先队列维护分组内的元素数目,确保每次都能选择当前元素数目最少的分组进行填充,实现了O(nlogn)的时间复杂度。
471

被折叠的 条评论
为什么被折叠?



