题目
输入输出样例
题目大意:
对于数组大小为 n 的两个数组 a,b,在a上进行 k 次交换,使得
∑
i
=
1
n
∣
a
i
−
b
i
∣
\sum_{i=1}^n{|a_i-b_i|}
∑i=1n∣ai−bi∣ 最大。
其实对于绝对值计算,可以等价于为数字加上+,-的符号,例如:
a
i
a_i
ai=3,
b
i
b_i
bi=1,则|
a
i
−
b
i
a_i-b_i
ai−bi|=+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|
∣ai−bi∣=
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
∣ai−bi∣+∣aj−bj∣=ai+aj−bi−bj
交换后:
∣
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
∣ai−bj∣+∣aj−bi∣=ai+bi−aj−bj
做差为:
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))
2∗bi−2∗aj=2∗min(ai,bi))−2∗max(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
∣ai−bi∣+∣aj−bj∣=ai+aj−bi−bj
交换后:
∣
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
∣ai−bj∣+∣aj−bi∣=ai+aj−bi−bj
做差为: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)) 2∗min(ai,bi))−2∗max(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。一看到交换还有绝对值,就觉得好麻烦,但是没想到这个竟然可以量化计算。