zoukankan      html  css  js  c++  java
  • P1966 火柴排队

    传送门

    显然有一个想法,把 $A,B$ 从小到大一一对应,这样距离最小,证明的话好像挺显然的

    设 $A_i<A_{i+1}$ ,$B_{i}<B_{i+1}$,那么如果 $A_i$ 对应 $B_i$,$A_{i+1}$ 对应 $B_{i+1}$

    距离为 $(A_i-B_i)^2+(A_{i+1}-B_{i+1})^2=A_{i}^{2}-2A_iB_i+B_{i}^2+A_{i+1}^{2}-2A_{i+1}B_{i+1}+B_{i+1}^2$

    如果 $A_i$ 对应 $B_{i+1}$ ,$A_{i+1}$ 对应 $B_{i}$ 那么距离同样可以算出,为

    $A_{i}^2-2A_{i}B_{i+1}+B_{i+1}^2+A_{i+1}^2-2A_{i+1}B{i}+B_{i+1}^2$

    两式相减,得到 $-2(A_iB_i+A_{i+1}B_{i+1}-A_{i+1}B_{i}-A_{i}B_{i+1}) = -2(A_i(B_i-B_{i+1})+A_{i+1}(B_{i+1}-B_i)) = -2((A_i-A_{i+1})(B_i-B_{i+1}))$

    因为 $A_i<A_{i+1}$ ,$B_{i}<B_{i+1}$,所以上式小于 $0$

    所以按从小到大一一对应是最优的

    然后考虑交换次数怎么求,显然 $B$ 的某个交换 $A$ 都有对应的交换,两者等价

    所以只要考虑 $A$ 怎么交换就行。每个火柴高度各不相同,确定了 $A$ 和 $B$ 的唯一的对应关系,所以我们知道每个 $A_{i}$ 最终的位置

    设初始位置为 $i$ 的火柴最终要到达位置 $C_i$,那么我们可以发现 $C_i$ 是一个 $1$ 到 $n$ 的排列

    而且最终交换完成后,$C_i$ 会变成 $1,2,3,...,n$ 的样子

    考虑用最少的步数把 $C_i$ 排序,显然这个就是答案,可以证明最小步数等于初始时 $C_i$ 的逆序对数量

    证明如下:

    考虑一次交换,它要么减少 $0$ 逆序对,要么减少 $1$ 逆序对,而最终状态的逆序对数量为 $0$(也是唯一逆序对为 $0$ 的状态)

    考虑冒泡排序的过程,每次选择 $i<j$ 且 $C_i>C_j$ 的数对进行交换,这样最终一定可以达到最终状态

    而且发现冒泡排序时,每次交换都会减少 $1$ 逆序对,所以我们交换时就可以模拟冒泡排序,达到最终状态

    综上,每次交换逆序对最多减少 $1$,且总有交换使得逆序对减少 $1$,所以逆序对数量就是最少交换次数

    我们可以用树状数组求逆序对数量

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e6+7,mo=99999997;
    int n,c[N];
    struct dat{
        int v,id;
        inline bool operator < (const dat &tmp) const {
            return v<tmp.v;
        }
    }a[N],b[N];
    int t[N];
    ll ans;
    inline void add(int x) { while(x<=n) t[x]++,x+=x&-x; }
    inline int ask(int x) { int res=0; while(x) res+=t[x],x-=x&-x; return res; }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) a[i].v=read(),a[i].id=i;
        for(int i=1;i<=n;i++) b[i].v=read(),b[i].id=i;
        sort(a+1,a+n+1); sort(b+1,b+n+1);
        for(int i=1;i<=n;i++) c[a[i].id]=b[i].id;
        for(int i=n;i;i--)
            ans+=ask(c[i]),add(c[i]);
        printf("%lld
    ",ans%mo);
        return 0;
    }
  • 相关阅读:
    怎么查看京东店铺的品牌ID
    PPT编辑的时候很卡,放映的时候不卡,咋回事?
    codevs 1702素数判定2
    codevs 2530大质数
    codevs 1488GangGang的烦恼
    codevs 2851 菜菜买气球
    hdu 5653 Bomber Man wants to bomb an Array
    poj 3661 Running
    poj 1651 Multiplication Puzzle
    hdu 2476 String Painter
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11367764.html
Copyright © 2011-2022 走看看