以样例为例,我们这样排列数字
枚举所有人最多不能超过
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;
}