将 看作是一段区间,那么考虑每次交换操作的贡献:
可以发现两区间无交集无论如何交换都满足其贡献 (事实上,如果令 ,那么 ),而有交集则 ,所以一定是尽量地选择有无集的区间交换。
引理: 时,「操作刚好 次」和「操作不超过 次」是等价的。
证明:将「操作不超过 次」的最优解执行完后,因为 ,根据鸽巢原理, 或者 的情况必然有一个的数量大于等于 ,那么反复交换这两个区间直到达到 次即可。
那么根据引理,将所有 和 分别从小到大、从大到小 sort 一遍,从前往后扫一遍,当后者大于前者时就将贡献加上,这样做能够使贡献最大化。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<vector> #include<ctime> #include<cstdlib> using namespace std; inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } #define mp make_pair typedef pair<int,int> pii; typedef long long ll; const int N=5e5+10; int l[N],r[N],x[N],y[N]; int main() { int n=read(),k=read(); for(int i=1;i<=n;i++)x[i]=read(); for(int i=1;i<=n;i++)y[i]=read(); for(int i=1;i<=n;i++)l[i]=min(x[i],y[i]),r[i]=max(x[i],y[i]); if(n==2) { if(k%2)swap(x[1],x[2]); printf("%d",abs(x[1]-y[1])+abs(x[2]-y[2])); } else { sort(l+1,l+n+1,greater<int>()),sort(r+1,r+n+1); ll ans=0; for(int i=1;i<=n;i++)ans+=abs(y[i]-x[i]); for(int i=1;i<=min(n,k);i++)if(r[i]<l[i])ans+=(l[i]-r[i])*2; printf("%lld",ans); } return 0; }