2021牛客暑期多校训练营1-Game of Swapping Numbers

题目链接

题意:现给你两个数组A,B,你需要交换k次b内元素,问交换后 ∑ 1 n \sum_1^n 1nabs(ai-bi)最大为多少

解析:
当没有k的限制时:
①如果ai>=bi,则abs(ai-bi)=ai-bi,即A,B数组中有n个元素做被减数,n个做减数,ans = ∑ 1 n 被 减 数 \sum_1^n被减数 1n- ∑ 1 n 减 数 \sum_1^n减数 1n,要获得最大的ans,则被减数应该是A,B中最大的n个元素,减数为A,B中最小的n个元素,用C数组表示被减数元素集合,D数组表示减数元素集合,且显然有sizeof©=sizeof(D)
②那么需要交换怎样的bi,bj呢?有分析①易知我们要使减数与被减数一一配对,则当a[i],b[i]属于C,而a[j],b[j]属于D时,我们要交换b[i]和b[j];
当存在k限制且n>2时:
①若k>=sizeof©,我们通过sizeof©次交换可以使减数与被减数一一配对,剩下的k次我们可以交换同为减数或被减数的元素,这样不会导致结果变劣
②若k Δ \Delta Δans=2*(min(ai,bi)-max(aj,bj)),所以我们可以将相同下标处同属C的的较小值放入一新数组E,同属于D的较大值放入一新数组F,然后将E从大到小排序,F从小到大排序,则ans = ∑ 1 n \sum_1^n 1nabs(ai-bi)+ ∑ 1 k 2 ∗ ( e i − f i ) \sum_1^k2*(ei-fi) 1k2(eifi)
当存在k限制且n等于2时:
①此时当k>=sizeof©时,交换使减数与被减数一一配对后,我们再进行交换是会影响到结果的,可能导致结果变劣,比如n=2,k=4,初始ans不为最大时,我们交换一次后ans为最大值,我们还要交换三次,但我们只有一种交换方法,到最后数组与初始数组一致
②所以当n为2时答案即为b1,b2交换k%2次的结果

AcCode

#include
#include
#include
#include
#include
#include

#define inf 0x3f3f3f3f
#define ll long long

using namespace std;

const int N = 5e5 + 100;

int a[N], b[N], arr[N << 1], c[N], d[N], e[N], f[N];
map<int, int> rmap;
vector<int> vec1, vec2;

inline int mabs(int a) { return (a >= 0) ? a : -a; }

inline int min(int a, int b) { return (a >= b) ? b : a; }

inline int max(int a, int b) { return (a >= b) ? a : b; }

signed main() {
	/*ios::sync_with_stdio(false);
	cin.tie(0);*/
	int n, cnt = 0, k;
	ll ans = 0;
	scanf("%d %d", &n, &k);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), arr[++cnt] = a[i];
	for (int j = 1; j <= n; j++) scanf("%d", &b[j]), arr[++cnt] = b[j], ans = ans + 1ll * mabs(a[j] - b[j]);
	if (n == 2) {
		if (k % 2 == 0) {
			printf("%lld\n", ans);
			//cout << ans << endl;
		}
		else if (k & 1) {
			//cout << abs(a[2] - b[1]) + abs(a[1] - b[2]) << endl;
			printf("%d\n", mabs(a[2] - b[1]) + mabs(a[1] - b[2]));
		}
		return 0;
	}
	sort(arr + 1, arr + 1 + cnt, greater<int>());//nlogn
	int maxup = 0;
	int fcnt = 0, ecnt = 0;
	int sign = arr[cnt / 2];
	for (int i = cnt / 2; i && arr[i] == sign; i--) maxup++;

	for (int i = 1; i <= n; i++) {
		if (a[i] > sign) c[i] = a[i];
		else if (a[i] == sign && maxup) maxup--, c[i] = a[i];
		else c[i] = -a[i];
	}
	for (int i = 1; i <= n; i++) {
		if (b[i] > sign) d[i] = b[i];
		else if (b[i] == sign && maxup) maxup--, d[i] = b[i];
		else d[i] = -b[i];
	}
	for (int i = 1; i <= n; i++) {
		if (a[i] == c[i] && b[i] == d[i]) {
			//vec1.push_back(min(a[i], b[i]));
			e[++ecnt] = min(a[i], b[i]);
		}
		else if (a[i] == -c[i] && b[i] == -d[i]) {
			//vec2.push_back(max(a[i], b[i]));
			f[++fcnt] = max(a[i], b[i]);
		}
	}
	sort(e + 1, e + 1 + ecnt, greater<int>());
	//sort(vec1.begin(), vec1.end(), greater());
	sort(f + 1, f + 1 + fcnt);
	//sort(vec2.begin(), vec2.end());
	if (ecnt <= k) {
		for (int i = 1; i <= ecnt; i++) {
			ans = ans + 2ll * (e[i] - f[i]);
		}
	}
	else {
		for (int i = 1; i <= k; i++) ans = ans + 2ll * (e[i] - f[i]);
	}
	printf("%lld\n", ans);
}

你可能感兴趣的:(补题,算法,贪心算法)