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 需要特殊判断。
求最优对换解:
考虑对于 AiA_iAi 和AjA_jAj,如果需要答案变优,则需要两个区间没有交(区间是[min(Ai,Bi),max(Ai,Bi)][\min(A_i,B_i),\max(A_i,B_i)][min(Ai,Bi),max(Ai,Bi)]画画图即可看出),并且变优 2×[min(Ai,Bi)−max(Aj,Bj)]2×[\min(A_i,B_i) - \max(A_j, B_j)]2×[min(Ai,Bi)−max(Aj,Bj)]。因此只需要将所有的 2×min(Ai,Bi)2×\min(A_i, B_i)2×min(Ai,Bi) 和 2×max(Ai,Bi)2×\max(A_i, B_i)2×max(Ai,Bi)排序,依次取前 kkk 大相减取和即可。
#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;
}