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;
    }
  • 相关阅读:
    linux上mysql安装详细教程
    druid部署
    druid.io本地集群搭建 / 扩展集群搭建
    CentOS7.1.x+Druid 0.12 集群配置
    Python小项目四:实现简单的web服务器
    hadoop学习---运行第一个hadoop实例
    Hadoop集群完全分布式坏境搭建
    mysql备份与恢复
    mysql登录的三种方式
    nginx代理,负载均衡
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11367764.html
Copyright © 2011-2022 走看看