【题解】模拟赛11.22T1 玩具

【题解】模拟赛11.22T1 玩具
【题解】模拟赛11.22T1 玩具
以样例为例,我们这样排列数字
【题解】模拟赛11.22T1 玩具

枚举所有人最多不能超过 i i i个玩具,就把超过的部分买回来
然后我自己至少得拥有 i + 1 i+1 i+1个玩具,所以如果不够的话,从下面取
可以用线段树维护,所以需要一开始离散化,每次数据结构套离散化真的挺麻烦的

Code:

#include <bits/stdc++.h>
#define maxn 100010
#define ls rt << 1
#define rs rt << 1 | 1
#define LL long long
using namespace std;
struct data{
	int cnt, id;
}v[maxn];
struct Seg{
	int l, r, cnt;
	LL sum;
}seg[maxn << 2];
struct node{
	int a, c;
}a[maxn];
vector <node> w[maxn];
int val[maxn], pos[maxn], n, m, p, point[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

bool cmp(data x, data y){
	return x.cnt > y.cnt;
}

bool cmp1(node x, node y){
	return x.a < y.a;
}

void pushup(int rt){
	seg[rt].cnt = seg[ls].cnt + seg[rs].cnt;
	seg[rt].sum = seg[ls].sum + seg[rs].sum;
}

void build(int rt, int l, int r){
	seg[rt].l = l, seg[rt].r = r;
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(ls, l, mid), build(rs, mid + 1, r);
}

void update(int rt, int pos, int delta){
	if (seg[rt].l == seg[rt].r){
		seg[rt].cnt += delta, seg[rt].sum += val[pos] * delta;
		return;
	}
	if (seg[ls].r >= pos) update(ls, pos, delta);
	else update(rs, pos, delta);
	pushup(rt);
}

LL query(int rt, int x){
	if (seg[rt].l == seg[rt].r) return 1LL * x * val[seg[rt].l];
	if (seg[ls].cnt >= x) return query(ls, x);
	else return seg[ls].sum + query(rs, x - seg[ls].cnt);
}

int main(){
	n = read(), m = read();
	for (int i = 1; i <= m; ++i){
		a[i].a = read(), a[i].c = read();
		++v[a[i].c].cnt;
	}
	for (int i = 1; i <= n; ++i) v[i].id = i;
	sort(v + 1, v + 1 + n, cmp);
	for (int i = 1; i <= n; ++i) pos[v[i].id] = i;
	sort(a + 1, a + 1 + m, cmp1);
	for (int i = 1; i <= m; ++i){
		if (a[i].a != a[i - 1].a) ++p;
		int id = pos[a[i].c];
		w[id].push_back((node){a[i].a, p});
		a[i].c = p, val[p] = a[i].a;
	}
	build(1, 1, p);
	for (int i = 1; i <= m; ++i) update(1, a[i].c, 1);
	LL sum = 0, ans = 1e15, num = 0;
	for (int i = m; i; --i){
		for (int j = 1; j <= n; ++j)
			if (w[j].size() - point[j] > i){
				while (w[j].size() - point[j] > i) ++num, sum += w[j][point[j]].a, update(1, w[j][point[j]].c, -1), ++point[j];
			} else break;
		if (num <= i) ans = min(ans, sum + query(1, i + 1 - num));
		else ans = min(ans, sum);
	}
	printf("%lld\n", ans);
	return 0;
}
上一篇:CS144学习(2)TCP协议实现


下一篇:lazyMan