T24759 Cup#182-5 平行分班II
模拟赛不会系列。。。
这道题要求最小的极差(所选元素相差的最大值),最小的最大,想到了二分。
但是我菜,找不到什么单调性。
看了标程,发现可以用堆来搞定。相关算法可以从P1631和P2085看到。
思路是将每一组分别排序,然后每组预先选取第1到第c[i]个。算出一个最初的ans。
然后可以每次更新答案,删除掉其中的最小值,插入下一个元素到堆里面去。同时维护新的ans。
更新到其中任意一组没有下一个的时候就break掉。然后输出ans即可。
代码:
#include<cstdio>
#include<queue>
#include<algorithm>
const int maxn = 100005, maxm = 1000005;
struct Nodes
{
int val, belong;
bool operator < (const Nodes &rhs) const
{
return val > rhs.val;
}
} s[maxm];
int tot;
std::priority_queue<Nodes> q;
int m[maxn], c[maxn];
int start[maxn], end[maxn], l[maxn], r[maxn];
int pos[maxn];
int maxx;
int n, ans;
bool cmp(const Nodes x, const Nodes y)
{
return x.val < y.val;
}
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
return s * ans;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++)
{
m[i] = read(), c[i] = read();
start[i] = tot + 1, end[i] = tot + m[i];
for(int j = 1; j <= m[i]; j++)
{
s[++tot] = (Nodes){read(), i};
}
}
for(int i = 1; i <= n; i++) std::sort(s + start[i], s + end[i] + 1, cmp);
for(int i = 1; i <= n; i++)
{
for(int j = start[i]; j <= start[i] + c[i] - 1; j++)
{
q.push(s[j]);
maxx = std::max(maxx, s[j].val);
}
pos[i] = start[i] + c[i] - 1;
}
ans = maxx - q.top().val;
while(2333)
{
Nodes u = q.top(); q.pop();
int i = u.belong;
if(pos[i] == end[i]) break;
q.push(s[++pos[i]]);
maxx = std::max(maxx, s[pos[i]].val);
ans = std::min(ans, maxx - q.top().val);
}
printf("%d\n", ans);
return 0;
}