题目链接
https://ac.nowcoder.com/acm/contest/11166/G
题目大意
给定两个长度为
n
(
2
≤
n
≤
5
∗
1
0
5
)
n(2 \leq n \leq 5*10^5)
n(2≤n≤5∗105)的数组A,B
(
−
1
0
8
≤
A
i
,
B
i
≤
1
0
8
)
(-10^8 \leq A_i,B_i \leq 10^8)
(−108≤Ai,Bi≤108),现在对数组A操作恰好
k
(
0
≤
k
≤
1
0
18
)
k(0 \leq k \leq 10^{18})
k(0≤k≤1018)次。
每次操作,任意选择两个元素
A
i
,
A
j
(
1
≤
i
<
j
≤
n
)
A_i,A_j(1 \leq i <j \leq n)
Ai,Aj(1≤i<j≤n),并交换他们。
求最小的
∑
i
=
1
n
∣
A
i
−
B
i
∣
\sum_{i=1}^n{|A_i-B_i|}
∑i=1n∣Ai−Bi∣。
题解
由于两个数在数轴上的距离可以通过|a-b|来得出,故我们可以用数轴形象化差值。如图:
这里用
S
i
S_i
Si表示
A
i
A_i
Ai与
B
i
B_i
Bi的距离,由图可知,经过调换可以额外得到
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))的值。所以可以运用贪心得到该式的最大值,再加上原来的差值
∑
i
=
1
n
∣
A
i
−
B
i
∣
\sum_{i=1}^n{|A_i-B_i|}
∑i=1n∣Ai−Bi∣即可。
因为恰好移动k步,所以我们将
m
i
n
(
A
i
,
B
i
)
min(A_i,B_i)
min(Ai,Bi)和
m
a
x
(
A
j
,
B
j
)
max(A_j,B_j)
max(Aj,Bj)的值进行排序,将前k大的
m
i
n
(
A
i
,
B
i
)
min(A_i,B_i)
min(Ai,Bi)与前k小的
m
a
x
(
A
j
,
B
j
)
max(A_j,B_j)
max(Aj,Bj)相减。由于k的值可能很大,所以当
m
i
n
(
A
i
,
B
i
)
≤
m
a
x
(
A
j
,
B
j
)
min(A_i,B_i) \leq max(A_j,B_j)
min(Ai,Bi)≤max(Aj,Bj)是停止判断,即达到最大值,剩下的步数用来反复横跳(每组起码有两个min的值或max的值【抽屉原理】【n>2】)。
且当n==2时无论怎么移动
S
1
和
S
2
S_1和S_2
S1和S2,他们的总长度都不会增长(如图),所以额外计算
S
1
+
S
2
S_1+S_2
S1+S2即可
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,k;
long long a[N],b[N],num[N];
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
long long ans=0;
for(int i=1;i<=n;i++)
{
long long x;
scanf("%lld",&x);
if(x>a[i])
swap(x,a[i]);
b[i]=x;
ans+=abs(a[i]-b[i]); //计算最初的差值
}
sort(a+1,a+n+1);
sort(b+1,b+n+1);
if(n==2 && k%2)
ans=abs(a[1]-b[2])+abs(a[2]-b[1]);
else
for(int i=1;i<=k;i++)
{
if(b[n-i+1]-a[i]>0) //若满足条件,则后续都不用计算
ans+=2*(b[n-i+1]-a[i]); //计算极差并累加
else
break;
}
printf("%lld\n",ans);
}
总结
这是一道贪心题,代码实现很简单,思路一时半会可能想不到,只要做出图就方便理解了。