zoukankan      html  css  js  c++  java
  • 测试5T2-手套

    问题描述
    你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下。N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起。由于手套比较多,你每次只能交换相邻两个手套。请你计算最少要交换几次才能把手套排整齐。
    输入格式
    输入第一行一个N,表示手套对数。
    第二行有2N个整数,描述了手套的颜色。每个数都在0~N-1之间,且每个数字都会出现恰好两次。
    输出格式
    一行,包含一个数,表示最少交换次数。
    样例输入
    2
    0 1 0 1
    样例输出
    1
    数据范围
    30%的数据N≤9;
    60%的数据N≤1000;
    100%的数据N≤200,000。

    这道题题目看错,吐血~~我以为是求多少次把手套从大到小排好序~~

    这题就是先考虑一下贪心做法——每次找到一对手套的前半只,把后半只换到它后面,不会对原序列其他数产生影响

    这样我们可以O(n)确定一下每只手套的最终位置(全部靠前放,就是把后面那只放到前面那只的后面)

    然后其实这样的操作的总数就是求逆序对数

    所以重新编号+逆序对就可以A啦!

    命题:上述操作的次数等于重新编号后数组的逆序对个数

    引理:先对哪对手套进行操作并不影响答案(口糊见上)

    证明:我们先把剩余数组中重新编号最小那对手套换完。所以我们只需要交换那后半只手套到第二的位子就可以了

    要交换的次数是原序列中编号<后半只手套 且 重新编号后编号>这对手套的

    得证啦!

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define lowbit(x) x&(-x)
    #define N 400005
    using namespace std;
    #define ll long long
    ll ans,n,i,bianhao[N],b[N],x,tree[N];
    bool flag[N];
    void update(ll u)
    {
        for(ll j=u;j<=n;tree[j]++,j+=lowbit(j));
    }
    ll getsum(ll u)
    {
        ll tot=0;
        for(ll j=u;j;tot+=tree[j],j-=lowbit(j));
        return tot;
    }
    int main()
    {
        ios::sync_with_stdio(false); 
        cin>>n;
        n*=2;
        ll q=0;
        for(ll i=1;i<=n;i++)
        {
            cin>>x;
            if(!flag[x])
            {
                flag[x]=1;
                bianhao[x]=++q;
            }
            b[i]=bianhao[x];
        }
        for(ll i=n;i>=1;i--)
        {
            ans+=getsum(b[i]-1);
            update(b[i]);    
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    小程序使用字体图标-阿里版
    vue项目安装vux
    JS日期相减得到天数
    vue的Vuex
    ES6的Promise
    根据坐标拖动(简单)
    JSP 第三周作业
    JSP第二次作业(2)
    第二次JSP作业
    JSP 第一次作业
  • 原文地址:https://www.cnblogs.com/dancer16/p/7040172.html
Copyright © 2011-2022 走看看