Loading

QOJ 3044 H. Maximizer

算法

仔细做题可以发现, 一定是上半区下半区匹配, 特别的, 对于 \(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();
    else
        calc2();
    return 0;
}

抄的机房巨佬

总结

不要被特殊样例诈骗啦!

主要没想到的是匹配的最优方法, 多做做题吧, 毕竟不是天赋哥

posted @ 2024-11-28 16:48  Yorg  阅读(10)  评论(0)    收藏  举报