洛谷 P5426 题解

Posted peterpang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P5426 题解相关的知识,希望对你有一定的参考价值。

题目传送门

题意概述

  • 给定一个长度为 \\(2\\times n\\) 的布尔数列,求交换的最小次数,使得左右两个长度为 \\(n\\) 的数列的逆序对的数量相同。

思考

首先,我们令 \\(\\Delta=f(1,n)-f(n+1,2\\times n)\\), 其中 \\(f(i,j)\\) 表示这个数列下标在 \\(i\\)\\(j\\) 之间的这个子数列的逆序对数,那么答案就是使 \\(\\Delta=0\\) 的最小次数。举个例子:

5
0 0 0 1 0 1 0 0 0 1

在左边 \\(n\\) 个数中,互相交换位置,改变的逆序对数 \\(\\delta=\\pm 1\\)

但是,在中间的 0 1 交换就会造成较大的变动。

具体的,左侧的所有 1 与第 \\(n\\) 号位置的 0 组成的逆序对消失了,同时第 \\(n+1\\) 号位的新的 1 与后面所有的 0 会产生新的逆序对。

所以,\\(\\Delta\\) 改变的数量为:\\(\\text{Left1}+\\text{Right1}-n=sum-n\\)。其中 \\(sum\\) 为整个数列中 1 的个数,即数列元素之和。

但是,如果中间的两个元素一样怎么办?再看一个例子:

5
0 1 0 1 1 0 0 0 1 1

当然,最优方法显然并不涉及到中间两者的交换,仅供演示。

我们考虑将最靠近 \\(n\\) 的左侧第一个 0最靠近 \\(n+1\\) 的右侧第一个 1 分别换到 \\(n\\)\\(n+1\\) 两个位置,再进行一次交换。此时记录这次交换所需要的次数,以及交换后 \\(\\Delta\\) 的值。

所以,这种交换的次数最多为左侧 0 的个数,即不超过 \\(n\\),可以直接进行枚举。

同样的,我们对于另一种操作,也进行差不多的枚举。

时间复杂度 \\(\\Theta(n)\\),似乎很容易被 \\(10^5\\) 的数据范围骗到。

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=200005;
int x[N],y[N],z[N],n;
ll ans,ansL,ansR;
int L0[N],L1[N],R0[N],R1[N];
int L0siz=0,R1siz=0,R0siz=0,L1siz=0;
ll sum=0;
void merge_sort(int L,int R)
{
    ans=0;
    int zr=0;
    for(int i=R;i>=L;i--)
    {
        if(!x[i]) zr++;
        else ans+=zr;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=2*n;i++)
	{
		scanf("%d",&x[i]);
		sum+=x[i];
	}
    merge_sort(1,n);
    ansL=ans;
    merge_sort(n+1,2*n);
    ansR=ans;
    ll Dt=ansL-ansR;
    if(Dt==0)
    {
        printf("0");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        if(x[i]==0) L0[++L0siz]=i;
        else L1[++L1siz]=i;
    }
    for(int i=2*n;i>=n+1;i--)
    {
        if(x[i]==1) R1[++R1siz]=i;
        else R0[++R0siz]=i;
    }
    ll ans=abs(Dt);
    ll step=0;
    while(L0siz>0&&R1siz>0)
    {
        int LL=L0[L0siz],RR=R1[R1siz];
        int tmp=(n-LL)-(RR-n-1)-(sum-n);
        Dt+=tmp;
        step+=(n-LL)+(RR-n-1)+1;
        L0siz--;
        R1siz--;
        ans=min(ans,abs(Dt)+step);
    }
    Dt=ansL-ansR;
	step=0;
	while(L1siz>0&&R0siz>0)
	{
	    int LL=L1[L1siz],RR=R0[R0siz];
	    int tmp=(n-LL)-(RR-n-1)-(sum-n);
	    Dt-=tmp;
	    step+=(n-LL)+(RR-n-1)+1;
	    L1siz--;
	    R0siz--;
	    ans=min(ans,abs(Dt)+step);
    }
    printf("%lld",ans);
    return 0;
}

本文来自博客园,作者:peterpang,转载请注明原文链接:https://www.cnblogs.com/sng2018phy/p/15345559.html

以上是关于洛谷 P5426 题解的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1854 花店橱窗布置 分析+题解代码

洛谷P2832 行路难 分析+题解代码玄学最短路

洛谷 P2210 Haywire 题解报告

洛谷 P2194 HXY烧情侣Tarjan缩点 分析+题解代码

BZOJ2938 & 洛谷2444:[POI2000]病毒——题解

洛谷P1047校门外的树题解