• 【NOIP】提高组2013 火柴排队


    【题意】两列n个火柴,分别有高度ai和bi(同一列高度互不相同),每次可以交换一列中的两个相邻火柴,定义距离为∑(ai-bi)^2,求使距离最小的最少交换次数,n<=10^5。

    【算法】逆序对

    【题解】∑(ai-bi)^2=∑ai^2+∑bi^2-∑ai*bi,其中∑ai^2和∑bi^2为常数,则要使∑ai*bi最大。

    对于两个序列的∑ai*bi,根据排序不等式,有逆序和<=乱序和<=正序和。(可以理解为两数离得越近,乘积越大)

    将两序列各自离散化后,问题转化为使两序列每位数字相等

    为了方便统计,换种角度说就是A数组的每个数字需要移动到一个对应的位置,所以我们设置C数组表示A数组中每个数应该去的位置

    (具体操作中最方便的方法是:A和B排序,然后C[A[i].id]=B[i].id

    那么实际上我们就是要通过交换使C数组升序排列,问题转化为通过最少次交换相邻数字使一个序列升序排列

    要使交换次数最少,就使每次交换消除一个逆序对。如果不存在相邻逆序对,可以证明序列已经升序排列。

    所以答案是逆序对数,可以使用树状数组或归并排序求逆序对,复杂度O(n log n)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #define lowbit(x) x&-x
    #define ll long long
    using namespace std;
    const int maxn=100010,MOD=99999997;//ji de qu mo
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    int n,c[maxn],A[maxn];
    struct cyc{int num,id;}a[maxn],b[maxn];
    bool cmp1(cyc a,cyc b){return a.num<b.num;}
    bool cmp2(cyc a,cyc b){return a.id<b.id;}
    void insert(int x){for(int i=x;i<=n;i+=lowbit(i))c[i]++;}
    int query(int x){int ans=0;for(int i=x;i>=1;i-=lowbit(i))ans+=c[i];return ans;}
    int main(){
         n=read();
         for(int i=1;i<=n;i++)a[i].num=read(),a[i].id=i;
         for(int i=1;i<=n;i++)b[i].num=read(),b[i].id=i;
         sort(a+1,a+n+1,cmp1);sort(b+1,b+n+1,cmp1);
         for(int i=1;i<=n;i++)A[a[i].id]=b[i].id;
         ll ans=0;
         for(int i=1;i<=n;i++){
             insert(A[i]);
             ans+=i-query(A[i]);//
        }
        printf("%lld",ans%MOD);
        return 0;
    }
    View Code

    记得取模!

  • 相关阅读:
    requirejs小记
    backbone入门
    简单的javascript/css slider滑动条
    又一个简单试用的javascript Slider插件
    Hdu3926 Hand in Hand
    今天OJ升级的学习内容总结
    非常实用的PHP代码片段
    第一次面试经历
    PHP Filesystem 函数
    MFC实现 MSN QQ 窗口抖动
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7779102.html
Copyright © 2020-2023  润新知