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(2≤n≤5⋅105)的数组
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(−108≤Ai,Bi≤108),现在对数组
A
A
A操作恰好
k
(
0
≤
k
≤
1
0
18
)
k(0\le k \le 10^{18})
k(0≤k≤1018)次。
每次操作,任意选择两个元素
A
i
,
A
j
(
1
≤
i
<
j
≤
n
)
A_i,A_j(1\le i<j\le n)
Ai,Aj(1≤i<j≤n),并交换他们。
求最大的
∑
i
=
1
n
∣
A
i
−
B
i
∣
\sum\limits_{i=1}^n\left| A_i-B_i\right|
i=1∑n∣Ai−Bi∣。
题解
首先对于 n = 2 n=2 n=2的特殊情况进行进行考虑,此时交换只有一种方案,交换偶数次相当于不操作,即判断 k k k的奇偶性是否交换后直接计算答案即可。
当
n
>
2
n>2
n>2时,我们将
A
,
B
A,B
A,B数组的元素在数轴上表示,并连接对应的一对
A
x
,
B
x
(
1
≤
x
≤
n
)
A_x,B_x(1\le x\le n)
Ax,Bx(1≤x≤n),此时绝对值差即为线段长度。对于一组
A
i
,
A
j
(
1
≤
i
<
j
≤
n
)
A_i,A_j(1\le i<j\le n)
Ai,Aj(1≤i<j≤n)及其对应的
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
n>2时,根据抽屉原理,一定存在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;
}