G-Game of Swapping Numbers
讲题人做法
最优解转化:
考虑任意一个最优解,我们把交换后的数字重新放回原来的位置,相当于为每一个元素分配了它在答案中的符号。比如 A={0, 3}, B = {1, 2},最优解符号分配是 A={-0,+3}, B={-1,+2}。
考察符合要求的解符号分配规则,其实只要满足 A, B 中正号总和和负号总和相等,而 A、B 各自的正负号可以不一样。
注意:有可能出现正负号和实际绝对值相反的情况,这样如果不交换答案会更劣,我们求最优解不会影响。转化后的问题和原问题不完全相同,但是最优解相同!!!
结论:n>2时,恰好 k 步与至多 k 步是等价的,当 n>2 时,A 中一定至少存在两个 + 号或两个 - 号,此时如果我们交换这两个符号对应的数,则并不会使得原问题的解变得更劣。n=2 需要特殊判断。
求最优对换解:
考虑对于
A
i
A_i
Ai 和
A
j
A_j
Aj,如果需要答案变优,则需要两个区间没有交(区间是
[
min
(
A
i
,
B
i
)
,
max
(
A
i
,
B
i
)
]
[\min(A_i,B_i),\max(A_i,B_i)]
[min(Ai,Bi),max(Ai,Bi)]画画图即可看出),并且变优
2
×
[
min
(
A
i
,
B
i
)
−
max
(
A
j
,
B
j
)
]
2×[\min(A_i,B_i) - \max(A_j, B_j)]
2×[min(Ai,Bi)−max(Aj,Bj)]。因此只需要将所有的
2
×
min
(
A
i
,
B
i
)
2×\min(A_i, B_i)
2×min(Ai,Bi) 和
2
×
max
(
A
i
,
B
i
)
2×\max(A_i, B_i)
2×max(Ai,Bi)排序,依次取前
k
k
k 大相减取和即可。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
constexpr int N=200010;
int n,K;
int A[N],B[N];
int dmin[N],dmax[N];
int main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>K;
for(int i=1;i<=n;i++) cin>>A[i];
for(int i=1;i<=n;i++) cin>>B[i];
ll ans=0;
if(n==2&&(K&1)) swap(A[1],A[2]);
for(int i=1;i<=n;i++) ans+=abs(A[i]-B[i]);
if(n<=2) return cout<<ans<<'\n',0;
for(int i=1;i<=n;i++)
{
dmin[i]=2*min(A[i],B[i]);
dmax[i]=2*max(A[i],B[i]);
}
sort(dmin+1,dmin+1+n,[&](int a,int b){return a>b;});//从大到小
sort(dmax+1,dmax+1+n);// 从小到大
ll cur=ans;
for(int i=1;i<=n&&i<=K;i++) //前k大
{
cur+=dmin[i]-dmax[i];
ans=max(ans,cur);
}
cout<<ans<<'\n';
return 0;
}