1. 程式人生 > 其它 >Game of Swapping Numbers —— 1G

Game of Swapping Numbers —— 1G

Game of Swapping Numbers

題目描述

給定兩個長度為\(n\)的排列A,B\(,最大化\)\(\sum_{i = 1}^n |A_i - B_i|\),可以對\(A\)排列執行\(k\)次交換操作。

範圍

\(n \leq 5 \times 10^5,0 \leq K \leq 10^8,-10^8 \leq A_i,B_i \leq 10^8\)

題解

以下是官方題解:

最優解性質

​ 考慮任意一個最優解,我們把交換後的數字重新放回原來的位置,相當於為每一個元素分配了它在答案中的符號。比如 A={0, 3}, B = {1, 2},最優解符號分配是 A={-0,+3}, B={-1,+2}。

考察符合要求的解符號分配規則,其實只要滿足 A, B 中正號總和和負號總和相等,而 A、B 各自的正負號可以不一樣。

​ 注意:有可能出現正負號和實際絕對值相反的情況,但是如果交換這一對正負號,只會使得解變優,所以在題目求最優的前提下,正負號是可以隨意分配的。

假設我們能任意指定 k 來求最優解,相當於是把 A, B 合在一起排序,取最大的 n 個填正號,最小的 n 個填符號即可。

最少步數得到最優解

​ 考慮每一對元素 \(A_i,B_i\),若它們符號不同,則直接忽略這一對元素;否則,一對都是+的元素需要和一對都是-的元素進行交換才能儘快達到最優解。

結論:n>2時,恰好

k 步與至多 k 步是等價的

​ 當 n>2 時,A 中一定至少存在兩個 + 號或兩個 - 號,此時如果我們交換這兩個符號對應的數,則並不會使得原問題的解變得更劣。

​ n=2 需要特殊判斷。

求最優對換解

​ 考慮對於 A_i 和A_j,如果需要答案變優,則需要兩個區間沒有交,變優 2*[min(A_i,B_i) - max(A_j, B_j)]。

​ 將所有的 min(A_i, B_i) 和 max(A_i, B_i) 排序,依次取前 k 大相減取和即可。

程式碼

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int a[N];
int b[N];
#define ll long long
int read () {
	int q = 0,f = 1;
	char ch = getchar();
	while(!isdigit(ch)) {
		if(ch == '-')f = -1;
		ch = getchar();
	}
	while(isdigit(ch)) {
		q = q * 10 + ch - '0';
		ch = getchar();
	}
	return q * f;
}
bool cmp(int a,int b) {
	return a > b;
}
ll ans;

int main () {
	int n;int k;
	cin >> n >> k;
	for(int i = 1;i <= n; ++i) a[i] = read();
	for(int i = 1;i <= n; ++i) b[i] = read();
	for(int i = 1;i <= n; ++i) {
		if(a[i] < b[i]) swap(a[i],b[i]);
	}
	sort(a + 1,a + n + 1,cmp);
	sort(b + 1,b + n + 1,cmp);
	for(int i = 1,j = n;i <= n and k > 0; ++i) {
		if(a[j] < b[i]) swap(a[j],b[i]);
		j --;
		k --;
	}
	for(int i = 1;i <= n; ++i) {
		ans += abs(a[i] - b[i]);
	}
	cout << ans << endl;
	return 0;
}