算法
仔细做题可以发现, 一定是上半区下半区匹配, 特别的, 对于 \(N\) 为奇数的情况, 中间值可以任意归为上半区下半区
问题转化为将 \(A\) 任意上半区的数移动对应到 \(B\) 任意下半区的数, 完成之后 \(A\) , \(B\) 一定匹配
显然的, 将 \(A\) 中上半区的数和 \(B\) 中下半区的数挨个匹配即可, 每个匹配花费为位置之差, 当然也可以序列算出来求逆序对
特别的, 对于 \(N\) 为奇数, 我们将中间数归为上下半区分开计算, 显然最优
代码
#include<bits/extc++.h>
#define int long long
using namespace std;
const int maxn = 1e6 + 5;
int n,mid;
int a[maxn],b[maxn];
vector<int>v1,v2;
void calc2()
{for (int i = 1; i <= n; i++)if (a[i] > mid)v1.push_back(i);for (int i = 1; i <= n; i++)if (b[i] <= mid)v2.push_back(i);int ans = 0;for (int i = 0; i < (int)v1.size(); i++)ans += abs(v1[i] - v2[i]);cout << ans;
}
void calc1()
{for (int i = 1; i <= n; i++)if (a[i] >= mid)v1.push_back(i);for (int i = 1; i <= n; i++)if (b[i] <= mid)v2.push_back(i);int ans1 = 0;for (int i = 0; i < (int)v1.size(); i ++)ans1 += abs(v1[i] - v2[i]);v1.clear(),v2.clear();for (int i = 1; i <= n; i++)if (a[i] > mid)v1.push_back(i);for (int i = 1; i <= n; i++)if (b[i] < mid)v2.push_back(i);int ans2 = 0;for (int i = 0; i < (int)v1.size(); i ++)ans2 += abs(v1[i] - v2[i]);cout << min(ans1,ans2);}
signed main()
{scanf("%lld",&n);mid = (n + 1) / 2;for (int i = 1; i <= n; i++)scanf("%lld",a + i);for (int i = 1; i <= n; i++)scanf("%lld",b + i);if (n & 1)calc1();elsecalc2();return 0;
}
抄的机房巨佬
总结
不要被特殊样例诈骗啦!
主要没想到的是匹配的最优方法, 多做做题吧, 毕竟不是天赋哥