2021牛客暑期多校训练营1 G题

G题: Game of Swapping Numbers

原题链接:https://ac.nowcoder.com/acm/contest/11166/G

题目大意

给定两个长度为 n ( 2 ≤ n ≤ 5 ⋅ 1 0 5 ) n(2\le n\le 5·10^5) n(2n5105)的数组 A , B ( − 1 0 8 ≤ A i , B i ≤ 1 0 8 ) A,B(-10^8\le A_i,B_i\le 10^8) A,B(108Ai,Bi108),现在对数组 A A A操作恰好 k ( 0 ≤ k ≤ 1 0 18 ) k(0\le k \le 10^{18}) k(0k1018)次。
每次操作,任意选择两个元素 A i , A j ( 1 ≤ i < j ≤ n ) A_i,A_j(1\le i<j\le n) Ai,Aj(1ijn),并交换他们。
求最大的 ∑ i = 1 n ∣ A i − B i ∣ \sum\limits_{i=1}^n\left| A_i-B_i\right| i=1nAiBi

题解

首先对于 n = 2 n=2 n=2的特殊情况进行进行考虑,此时交换只有一种方案,交换偶数次相当于不操作,即判断 k k k的奇偶性是否交换后直接计算答案即可。

n > 2 n>2 n2时,我们将 A , B A,B A,B数组的元素在数轴上表示,并连接对应的一对 A x , B x ( 1 ≤ x ≤ n ) A_x,B_x(1\le x\le n) Ax,Bx(1xn),此时绝对值差即为线段长度。对于一组 A i , A j ( 1 ≤ i < j ≤ n ) A_i,A_j(1\le i<j\le n) Ai,Aj(1ijn)及其对应的 B i , B j B_i,B_j Bi,Bj,进行交换操作对绝对值差和的影响为 2 ∗ ( m i n ( A j , B j ) − m a x ( A i , B i ) ) 2*(min(A_j,B_j)-max(A_i,B_i)) 2(min(Aj,Bj)max(Ai,Bi))(即对于两组点对的连接所得线段中间部分是否重合的改变),那么为了使结果最大化,我们使min尽可能大,max尽可能小(通过取 A , B A,B A,B对应值中的 m i n , m a x min,max min,max值分数组存放排序实现),并只执行可以使结果增大的交换操作。
若以上过程结束后,仍有剩余步骤需执行,我们考虑以下策略:
对于两条重合的线段,我们交换其的左端点(或右端点),不会对他们的重合部分和另一端点的延长部分造成影响,且该端点延长部分只是从一条线段转换到了另一条线段上,即两条线段长度和不变。
参考下图:
在这里插入图片描述

(各颜色部分长度对应相等)
而当 n > 2 n>2 n2时,根据抽屉原理,一定存在2条 A A A端点在同侧的线段,而且通过上述操作,所有线段必然都是重合的(有重合部分才能使结果更大),那么我们必然可以交换一组点使得结果不变,重复此操作至完成k步(代码中直接跳过即可)

参考代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+5;
int N,K,A[MAXN],B[MAXN],_min[MAXN],_max[MAXN];
long long ans;
int main()
{
	cin>>N>>K;
	if(N==2){//n为2时特殊判断
		for(int i=1;i<=N;i++)scanf("%d",&A[i]);
		for(int i=1;i<=N;i++)scanf("%d",&B[i]);
		K%=2;
		if(K)swap(A[2],A[1]);
		printf("%d\n",abs(A[2]-B[2])+abs(A[1]-B[1]));
	}
	else{
		for(int i=1;i<=N;i++)scanf("%d",&A[i]);
		for(int i=1;i<=N;i++){
			scanf("%d",&B[i]);
			_min[i]=min(A[i],B[i]),_max[i]=max(A[i],B[i]),ans+=abs(a[i]-b[i]);//分类min与max,并初始化ans
		}
		sort(_min+1,_min+N+1);
		sort(_max+1,_max+N+1);
		//排序
		for(int i=1;i<=min(N,K);i++){
			if(_min[N+1-i]-_max[i]<0)break;//当操作会使结果减小时,停止并跳出
			ans+=2*(_min[N+1-i]-_max[i]);//可得到更优解,则更新ans
		}
		printf("%lld",ans);
	}
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值