zoukankan      html  css  js  c++  java
  • NOIP2013 火柴排队 题解

    题解


    首先的话,上个题目链接  https://www.luogu.com.cn/problem/P1966

    读懂了题目大意,稍微有点头绪

     

    我们发现要求这个和的最小值

     

    即min{∑(ai-bi)^2 (1<=i<=n)}

     

     展开,得min{∑(ai^2+bi^2-2*ai*bi)}=min{∑ai^2+∑bi^2-∑2*ai*bi}

     

    只需要关注2*Σ(a[i]*b[i])的值,使它最大就行了(因为a的平方+b的平方始终为定值)

    然后的话,这时候需要证明一下这个东西

    让b数组中第i小的数和a数组中第i小的数在同一个位置是最优的

     

    顺序之乘>=乱序之乘

    证明如下:

    我们可以设a<b,c<d

    猜测ac+bd一定是最大的。利用反证法。

     

    若ac+bd不是最大的,那么一定有比它更大的,只有ad+bc

     

    ac+bd<ad+bc

     

    ac-ad<bc-bd

     

    a*(c-d)<b*(c-d)//c-d<0

    那么就会得到a>b (什么鬼,矛盾,所以得证)

    所以我们知道

    对于有序数列k1~kn,p1~pn,

    k(1)p(1)+k(2)p(2)+……+k(n)p(n)一定是最大的

    于是这题变成了,我们要用最少多少次使得这两个序列变成所谓b数组中第i小的数和a数组中第i小的数在同一个位置

    我们用一个很巧妙的办法,设输入的序列分别为a,b;

    开一个数组c,令c[b[i]]=a[i]  (这时候如果c[i]=[i],他们就在同一个位置)

    于是我们只要愉快的求一下c数组的逆序对对数就是最终的answer!

    求逆序对,树状数组?

    像我这样的蒟蒻当然懒得写,二分归并不好嘛。

    于是A了一道很水的洛谷蓝题(?)

    code如下

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=99999997;
    ll n,p[100010],x[100010],ans=0;
    struct node
    {
        int data,position;
    }a[100010],b[100010];
    bool cmp1(node a,node b)
    {
        return a.data<b.data;
    }
    inline ll read()
    {
        char ch;
        ll res,sign=1;
        while((ch=getchar())<'0'||ch>'9')
          if(ch=='-') sign=-1;
        res=ch^48;
        while((ch=getchar())>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^48);
        return res*sign;//快读卡常,不过这题没用 
    }
    inline void msort(int s,int t)
    {
        if(s==t)return ;
        int mid=(s+t)/2;
        msort(s,mid);msort(mid+1,t);
        int i=s,k=s,j=mid+1;
        while(i<=mid && j<=t)
        {
            if(x[i]<=x[j])
            {
                p[k]=x[i];
                ++k;++i;
                
            }
            else
            {
                p[k]=x[j];
                ++k;++j;
                ans=(ans+mid-i+1)%mod;
                //ans要增加左边剩余区间的个数,用来统计逆序对 
            }
        }
        while(i<=mid)
        {
            p[k]=x[i];
            ++k;++i;
        }
        while(j<=t)
        {
            p[k]=x[j];
            ++k;++j;
        }
        for(int i=s;i<=t;i++)
        {
            x[i]=p[i];
        }
    }
    int main()
    {
        n=read();
         for(int i=1;i<=n;i++)
            scanf("%d",&a[i].data),a[i].position=i;
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i].data),b[i].position=i;
        sort(a+1,a+n+1,cmp1);
        sort(b+1,b+n+1,cmp1);
        for(register int i=1;i<=n;++i)
        {
            x[b[i].position]=a[i].position;
        }//记录位置 
        msort(1,n);//归并排序求逆序对 
        printf("%lld",ans);
        
        return 0;
    }

     

     

  • 相关阅读:
    tomcat https 启用8443加证书
    深刻理解Python中的元类metaclass(转)
    为什么数据科学家们选择了Python语言?
    谷歌如何管理世界上最聪明的工程师(转)
    前百度首席科学家张栋:36岁以前做到这8点再谈梦想(转)
    MySQL索引原理及慢查询优化(转)
    地理空间距离计算优化(转)
    Innodb中的事务隔离级别和锁的关系(转)
    关于大型网站技术演进的思考(转)
    应用引擎BAE3.0(转)
  • 原文地址:https://www.cnblogs.com/yjyl0098/p/13928555.html
Copyright © 2011-2022 走看看