$des$
有 $n$ 个物品,第 $i$ 个物品的价格是 $v_i$ ,有两个人,每个人都喜欢 $n$ 个物品中的一些物品。
要求选出正好 $m$ 个物品,满足选出的物品中至少有 $k$ 个物品被第一个人喜欢,$k$ 个物品被第二个人喜欢。并求出最小的价格和。
$sol$
将所有物品分成 $4$ 类
1. $a \cap b$
2. $a - a \cap b$
3. $b - a \cap b$
4. $全集 - a \cup b$
枚举 $1$ 选了多少个
此时 $2, 3$ 选多少个是固定的了
这样的话只需维护剩余元素的前 $x$ 小值之和
对顶堆维护
大根堆维护前 $x$ 小
查询时就是大根堆的权值之和
删除元素标记
维护剩余元素的前 $x$ 小值之和也可以用权值线段树
#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; #define gc getchar() inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } #define Rep(i, a, b) for(int i = a; i <= b; i ++) #define LL long long #define Fin(a) freopen(a, "r", stdin) #define Fout(a) freopen(a, "w", stdout) #define E return #define End cout << "\n" map <int, int> Map; int W[N]; int n, m, k, a, b; bool usea[N], useb[N]; priority_queue <int, vector <int>, less <int> > Big; priority_queue <int, vector <int>, greater <int> > Small; int szab[N], jsab; int sza[N], jsa; int szb[N], jsb; int sznot[N], jsnot; LL sum1[N], sum2[N], sum3[N]; int Size; LL Sum; void Update() { while(Big.size() && Map[Big.top()]) Map[Big.top()] --, Big.pop(); while(Small.size() && Map[Small.top()]) Map[Small.top()] --, Small.pop(); } int Now_size; int ato, bto, abto; void Add(int x) { Update(); while(Size < Now_size && Small.size()) { int topsmall = Small.top(); Small.pop(); Size ++, Sum += topsmall, Big.push(topsmall); } if(Size == Now_size) { if(Big.size() == 0) Small.push(x); else if(x < Big.top()) { int topbig = Big.top(); Sum += (x - topbig); Big.pop(); Big.push(x); Small.push(topbig); } return ; } if(Size < Now_size) { Big.push(x); Size ++; Sum += x; return ; } Update(); int topbig = Big.top(); if(x < topbig) { Sum += (x - topbig); Big.pop(); Big.push(x); Small.push(topbig); } else { Small.push(x); } } bool Judge() { if(m < k) return 1; if(jsab + jsa < k || jsab + jsb < k) return 1; if(k * 2 - jsab > m) return 1; return 0; } void RE() { cout << "error" << "\n"; } void Bef_work() { Rep(i, 1, n) { if(usea[i] && useb[i]) szab[++ jsab] = W[i]; else if(usea[i]) sza[++ jsa] = W[i]; else if(useb[i]) szb[++ jsb] = W[i]; else sznot[++ jsnot] = W[i]; } sort(szab + 1, szab + jsab + 1); sort(sza + 1, sza + jsa + 1); sort(szb + 1, szb + jsb + 1); sort(sznot + 1, sznot + jsnot + 1); Rep(i, 1, jsab) sum1[i] = sum1[i - 1] + szab[i]; Rep(i, 1, jsa) sum2[i] = sum2[i - 1] + sza[i]; Rep(i, 1, jsb) sum3[i] = sum3[i - 1] + szb[i]; if(Judge()) {puts("-1"); exit(0) ;} Rep(i, 1, jsab) Add(szab[i]); Rep(i, k + 1, jsa) Add(sza[i]); Rep(i, k + 1, jsb) Add(szb[i]); Rep(i, 1, jsnot) Add(sznot[i]); ato = min(k, jsa); bto = min(k, jsb); abto = 0; } bool Judge2(int x) { if(k - x > jsa || k - x > jsb || k * 2 - x > m) return 0; return 1; } void Del(int x) { Update(); Map[x] ++; int topbig = Big.top(); if(x <= topbig) { Size --, Sum -= x; } Update(); } LL Ask(int x) { Update(); while(Size > x && Big.size()) { int topbig = Big.top(); Size --, Sum -= topbig; Big.pop(); Small.push(topbig); Update(); } while(Size < x && Small.size()) { int topsmall = Small.top(); Size ++, Sum += topsmall; Small.pop(); Big.push(topsmall); Update(); } return Sum; } LL Calc(int x) { LL ret = 0; while(abto <= x && abto) { Del(szab[abto]); abto ++; } ret += sum1[abto - 1]; while(ato > k - x && ato) { Add(sza[ato]); ato --; } ret += sum2[ato]; while(bto > k - x && bto) { Add(szb[bto]); bto --; } ret += sum3[bto]; ret += Ask(m - k * 2 + x); return ret; } int main() { n = read(), m = read(), k = read(); Rep(i, 1, n) W[i] = read(); a = read(); Rep(i, 1, a) W[0] = read(), usea[W[0]] = 1; b = read(); Rep(i, 1, b) W[0] = read(), useb[W[0]] = 1; Now_size = m; Bef_work(); abto = 1; LL Answer = 1e18; Rep(i, 0, jsab) { if(!Judge2(i)) continue; Now_size = m - k * 2 + i; Answer = min(Answer, Calc(i)); } cout << (Answer == 1e18 ? -1 : Answer); return 0; }