2021牛客暑期多校训练营1 G-Game of Swapping Numbers(最优解转化+贪心)

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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值