2021暑期牛客多校1-G
阿新 • • 發佈:2021-07-20
G
首先,考慮如果不限制k的話,最優解如何構造。
顯然,答案最大的情況就是前n大的數加,後面的數減。
那麼如何說明總能構造出這種情況呢,
設 \(x_1,x_2\) 分別為 \(a,b\) 數列前 \(n\) 大的數字個數, \(y_1,y_2\) 分別為 \(a,b\) 數列前 \(n\) 小的個數。
顯然下面的等式成立
\[\begin{cases} x_1+y_1=x_2+y_2 \\ x_1+x_2=y_1+y_2 \end{cases} \]解得
\[\begin{cases} x_1=y_2 \\ y_1=x_2 \end{cases} \]所以總能將 \(a\) 中前 \(n\)
於是在不限制 \(k\) 的情況下,我們總能構造出最大的情況。
為了方便表述,將前 \(n\) 大記為正,前 \(n\) 小記為負,那麼當答案最大時所有的正的對面一定是負。
此時如果一個數組有兩個以上的正,則交換這兩個正不會影響答案,所以對於 \(n>2\) 的情況,恰好 \(k\) 步等價於至多 \(k\) 步,對於 \(n=2\) 單獨討論。
下面以至多 \(k\) 步為前提討論。
初始 \(a,b\) 數列,會出現正正,正負,負負三種配對情況。
-
正負不會和正負發生交換
顯然交換後答案不會更優
-
正正不會和正負發生交換
考慮 \((2)\) ,有一對正正就說明有一對負負,而正正和負負交換後答案一定會變優,所以如果正正和正負發生了交換,那麼交換過後的正正和負負交換會讓答案變得更優。考慮兩種交換最終對答案的貢獻,會發現是相等的,終局都是正負*3,而第二種交換法浪費了次數,所以不會選擇。
所以我們只需要考慮正正和負負交換即可,分別記為 \((s_1,s_2)\) , \((r_1, r_2)\) ,不難發現交換後貢獻為 \(2*(min(s_1,s_2)-max(r_1,r_2))\)
所以我們將初始陣列所有正正的配對按 \(min(s_1,s_2)\) 從大到小排,負負配對按 \(max(r_1,r_2)\)
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)
const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
int n, k;
ll ans;
ll a[500500], b[500500];
bool via[500500], vib[500500];
vector<int> q1, e[2];
bool cmp(cint x, cint y) {
if(x < 0) return y < 0 ? b[-x] < b[-y] : b[-x] < a[y];
else return y < 0 ? a[x] < b[-y] : a[x] < a[y];
}
void debug() {
for(int i=1; i<=q1.size(); i++) {
cout << q1[i-1] << ' ';
}
cout << endl;
}
int main() {
cin >> n >> k;
for(int i=1; i<=n; i++) cin >> a[i];
for(int i=1; i<=n; i++) cin >> b[i];
for(int i=1; i<=n; i++) ans += abs(a[i] - b[i]);
if(n == 2) {
if(k & 1) cout << abs(a[1]-b[2])+abs(a[2]-b[1]) << endl;
else cout << ans << endl;
} else {
for(int i=1; i<=n; i++) q1.push_back(i);
for(int i=1; i<=n; i++) q1.push_back(-i);
sort(q1.begin(), q1.end(), cmp);
for(int i=0; i<n; i++) {
if(q1[i] > 0) via[q1[i]] = 1;
else vib[-q1[i]] = 1;
}
for(int i=1; i<=n; i++) {
if(via[i] && vib[i]) e[1].push_back(max(a[i], b[i]));
if(!via[i] && !vib[i]) e[0].push_back(min(a[i], b[i]));
}
sort(e[0].begin(), e[0].end());
sort(e[1].begin(), e[1].end());
int le = e[0].size();
for(int i=1; i<=min(k,le); i++) {
if(e[0][le-i] <= e[1][i-1]) break;
ans += 2*(e[0][le-i]-e[1][i-1]);
}
// debug();
cout << ans << endl;
}
return 0;
}