【2021牛客多校】第一场G-Game of Swapping Numbers

题目

在这里插入图片描述

输入输出样例

在这里插入图片描述

题目大意:

对于数组大小为 n 的两个数组 a,b,在a上进行 k 次交换,使得 ∑ i = 1 n ∣ a i − b i ∣ \sum_{i=1}^n{|a_i-b_i|} i=1naibi 最大。
其实对于绝对值计算,可以等价于为数字加上+,-的符号,例如: a i a_i ai=3, b i b_i bi=1,则| a i − b i a_i-b_i aibi|=+3+(-1)。
先不考虑 k 步交换操作。由于 a 数组时可以交换的,所以题目可以看作是给给 a,b 数组的所有数字分配正负符号,满足正负符号的个数相等的条件下,使得所有数之和最大。
现在考虑 k :

结论:n>2时,恰好 k 步与至多 k 步是等价的

当 n>2 时,a 中一定至少存在两个 + 号或两个 - 号,此时如果我们交换这两个符号对应的数,则并不会使得原问题的解变得更劣,等于是无效操作,只为凑到 k 步。
n=2 需要特殊判断。

贪心思想

我们希望每一步交换都是得到当前最优的值,那么交换 a i , a j a_i,a_j ai,aj 增加的值能不能量化呢?我们来试一试。
对于 ( a i , b i ) , ( a j , b j ) (a_i,b_i) , (a_j,b_j) (ai,bi),(aj,bj) ,由于绝对值的存在, ∣ a i − b i ∣ |a_i-b_i| aibi= m a x ( a i , b i ) − m i n ( a i , b i ) max(a_i,b_i)-min(a_i,b_i) max(ai,bi)min(ai,bi),所以我们可以对 a,b 数组做交换的操作,使得 a 数组存取较大值,b 数组存取较小值,所以 a i > b i , a j > b j a_i > b_i , a_j > b_j ai>bi,aj>bj
接下来只需要讨论 b i b_i bi a j a_j aj 的大小,即可确定四个数字的大小关系,即可计算增加的值。
b i > a j b_i > a_j bi>aj 时:
初始: ∣ a i − b i ∣ + ∣ a j − b j ∣ = a i + a j − b i − b j |a_i-b_i|+|a_j-b_j|=a_i+a_j-b_i-b_j aibi+ajbj=ai+ajbibj
交换后: ∣ a i − b j ∣ + ∣ a j − b i ∣ = a i + b i − a j − b j |a_i-b_j|+|a_j-b_i|=a_i+b_i-a_j-b_j aibj+ajbi=ai+biajbj
做差为: 2 ∗ b i − 2 ∗ a j = 2 ∗ m i n ( a i , b i ) ) − 2 ∗ m a x ( a j , b j ) ) 2 * b_i - 2 * a_j=2*min(a_i,b_i))-2 * max(a_j,b_j)) 2bi2aj=2min(ai,bi))2max(aj,bj))

b i < a j b_i < a_j bi<aj 时:
初始: ∣ a i − b i ∣ + ∣ a j − b j ∣ = a i + a j − b i − b j |a_i-b_i|+|a_j-b_j|=a_i+a_j-b_i-b_j aibi+ajbj=ai+ajbibj
交换后: ∣ a i − b j ∣ + ∣ a j − b i ∣ = a i + a j − b i − b j |a_i-b_j|+|a_j-b_i|=a_i+a_j-b_i-b_j aibj+ajbi=ai+ajbibj
做差为:0(无意义交换)

所以,我们只要取出最大的 k 个 2 ∗ m i n ( a i , b i ) ) − 2 ∗ m a x ( a j , b j ) ) 2*min(a_i,b_i))-2 * max(a_j,b_j)) 2min(ai,bi))2max(aj,bj)) 即可得到最优值,如果还没有到 k 步差值就小于等于0,那么就可以提前结束了。

代码

#include <bits/stdc++.h>
#include <iostream>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
using namespace std;
const int MAXN = 5e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n,k,ans;
int a[MAXN],b[MAXN];

int main()
{
//	freopen("in.txt", "r", stdin);
	qc;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
		if(b[i]>a[i])//a[i]中为较大值  b[i]为较小值 
			swap(b[i],a[i]);
		ans+=(a[i]-b[i]); 
	}
	sort(a+1,a+1+n);//从小到大排序
	sort(b+1,b+1+n,greater<int>());//从大到小排序
	int tmp;
	for(int i=1;i<=k&&i<=n;i++)
	{
		tmp=2*(b[i]-a[i]);//交换的优化:2*(min(a1,b1)-max(a2,b2))
		if(tmp>0)
			ans+=tmp;
		else
			break;
	}
	cout<<ans<<endl;
	return 0;
}

碎碎念:

思路很巧妙,但是比赛的时候想不到,orz。一看到交换还有绝对值,就觉得好麻烦,但是没想到这个竟然可以量化计算。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值