[NOI2019] 序列 题解
CF436E Cardboard Box的升级版。
直接上来搞六个堆的反悔贪心。
思路
首先按照贪心的思路,将两个序列中最大 \(k\) 个直接选。
如果其中相同的小于 \(l\) ,我们考虑进行反悔贪心。
我们设当前序列相同的个数为 \(res\)。
我们每一回合都要让 \(res+1\)。
应该有四种情况:
-
选择一个之前选了 \(b\) 没选 \(a\) 的位置,将 \(a\) 选上,再丢掉一个只选了 \(a\) 的位置上的 \(a\)。
-
选择一个之前选了 \(a\) 没选 \(b\) 的位置,将 \(b\) 选上,再丢掉一个只选了 \(b\) 的位置上的 \(b\)。
-
选择一个之前选了 \(b\) 没选 \(a\) 的位置,和一个之前选了 \(a\) 没选 \(b\) 的位置,将 \(a,b\) 选上,再丢掉一个选了 \(a,b\) 的位置上的 \(a,b\)。
-
选择一个什么都没选位置上的 \(a,b\),将他们选上,再选择一个之前选了 \(b\) 没选 \(a\) 的位置,和一个之前选了 \(a\) 没选 \(b\) 的位置,将 \(a,b\) 丢掉。
列成式子就是:
-
\(a_{max}-a_{min}\)
-
\(b_{max}-b_{min}\)
-
\((a+b)_{max}-a_min-b_min\)
-
\(a_{max}+b_{max}-(a+b)_{min}\)
然后就可以开六个堆来维护这些式子。
最后,就是板子了。
Code
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int s = 0 , f = 1; char ch;
while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
while(isdigit(ch)) s = s * 10 + ch - '0' , ch = getchar();
return s * f;
}
const int maxn = 200010;
int t , n , k , l , vis[maxn] , a[maxn] , b[maxn];
struct edge
{
int id , num;
}al[maxn] , bl[maxn];
inline bool cmp(edge x , edge y)
{
return x.num > y.num;
}
struct qwq
{
int sum , id;
inline bool operator<(const qwq &tmp) const
{
return sum < tmp.sum;
}
inline bool operator>(const qwq &tmp) const
{
return sum > tmp.sum;
}
};
priority_queue<qwq , vector<qwq> , less<qwq> > q1 , q2 , q6;
priority_queue<qwq , vector<qwq> , greater<qwq> > q3 , q4 , q5;
/*
q1 -> a_i q2 -> b_i
q3 -> a_i q4 -> b_i
q5 -> a_i + b_i q6 -> a_i + b_i
*/
inline void solve(int i)
{
if(vis[i] == 0) q6.push({a[i] + b[i] , i});
if(vis[i] == 1) q2.push({b[i] , i}) , q3.push({a[i] , i});
if(vis[i] == 2) q1.push({a[i] , i}) , q4.push({b[i] , i});
if(vis[i] == 3) q5.push({a[i] + b[i] , i});
}
inline void init()
{
memset(vis , 0 , sizeof(vis));
while(q1.empty() == 0) q1.pop();
while(q2.empty() == 0) q2.pop();
while(q3.empty() == 0) q3.pop();
while(q4.empty() == 0) q4.pop();
while(q5.empty() == 0) q5.pop();
while(q6.empty() == 0) q6.pop();
}
signed main()
{
t = read();
while(t--)
{
init();
long long sum = 0 , res = 0;
//sum当前和,res当前匹配数量.
n = read() , k = read() , l = read();
for(int i = 1;i <= n;i++) a[i] = read() , al[i] = {i , a[i]};
for(int i = 1;i <= n;i++) b[i] = read() , bl[i] = {i , b[i]};
sort(al + 1 , al + n + 1 , cmp);
sort(bl + 1 , bl + n + 1 , cmp);
for(int i = 1;i <= k;i++)
sum += al[i].num , vis[al[i].id] = (vis[al[i].id] > 0 ? 3 : 1),
sum += bl[i].num , vis[bl[i].id] = (vis[bl[i].id] > 0 ? 3 : 2);
//vis_i == 1 只选 a_i
//vis_i == 2 只选 b_i
//vis_i == 3 都选了.
for(int i = 1;i <= n;i++)
res += (vis[i] == 3);
for(int i = 1;i <= n;i++) solve(i);
while(res < l)
{
long long lsum = -10000000000 , casel = 0;
while(q1.empty() == 0 && vis[q1.top().id] != 2) q1.pop();
while(q2.empty() == 0 && vis[q2.top().id] != 1) q2.pop();
while(q3.empty() == 0 && vis[q3.top().id] != 1) q3.pop();
while(q4.empty() == 0 && vis[q4.top().id] != 2) q4.pop();
while(q5.empty() == 0 && vis[q5.top().id] != 3) q5.pop();
while(q6.empty() == 0 && vis[q6.top().id] != 0) q6.pop();
if(q1.empty() == 0 && q3.empty() == 0)
{
if(lsum < q1.top().sum - q3.top().sum)
lsum = q1.top().sum - q3.top().sum , casel = 1;
}
if(q2.empty() == 0 && q4.empty() == 0)
{
if(lsum < q2.top().sum - q4.top().sum)
lsum = q2.top().sum - q4.top().sum , casel = 2;
}
if(q1.empty() == 0 && q2.empty() == 0 && q5.empty() == 0)
{
if(lsum < q1.top().sum + q2.top().sum - q5.top().sum)
lsum = q1.top().sum + q2.top().sum - q5.top().sum , casel = 3;
}
if(q3.empty() == 0 && q4.empty() == 0 && q6.empty() == 0)
{
if(lsum < q6.top().sum - q3.top().sum - q4.top().sum)
lsum = q6.top().sum - q3.top().sum - q4.top().sum , casel = 4;
}
if(casel == 1)
vis[q1.top().id] = 3 , vis[q3.top().id] = 0,
solve(q1.top().id) , solve(q3.top().id),
q1.pop() , q3.pop();
if(casel == 2)
vis[q2.top().id] = 3 , vis[q4.top().id] = 0,
solve(q2.top().id) , solve(q4.top().id),
q2.pop() , q4.pop();
if(casel == 3)
vis[q1.top().id] = 3 , vis[q2.top().id] = 3 , vis[q5.top().id] = 0,
solve(q1.top().id) , solve(q2.top().id) , solve(q5.top().id),
q1.pop() , q2.pop() , q5.pop();
if(casel == 4)
vis[q3.top().id] = 0 , vis[q4.top().id] = 0 , vis[q6.top().id] = 3,
solve(q3.top().id) , solve(q4.top().id) , solve(q6.top().id),
q3.pop() , q4.pop() , q6.pop();
sum += lsum , res++;
}
cout << sum << endl;
}
return 0;
}