zoukankan      html  css  js  c++  java
  • 二分·归并排序与树状数组之逆序对 hiho1141

    题目链接:二分·归并排序之逆序对

    题目大意:N个整数,第i个数表示等级第i低的船的火力值a[i],求A船比B船等级高,但是A船火力低于B船,相当于就是求逆序数吧

    解题思路:

    1. 把序列分成元素个数尽量相等的两半
    2. 把两半元素分别排序
    3. 把两个有序表合并成一个

    二分归并排序做法:

    /**************************************************************
        Problem:hiho 1141
        User: youmi
        Language: C++
        Result: Accepted
        Time:148ms
        Memory:7M
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define scs(a) scanf("%s",a)
    #define sclld(a) scanf("%I64d",&a)
    #define pt(a) printf("%d
    ",a)
    #define ptlld(a) printf("%I64d
    ",a)
    #define rep0(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define rep_1(i,n) for(int i=n;i>=1;i--)
    #define rep_0(i,n) for(int i=n-1;i>=0;i--)
    #define Max(a,b) (a)>(b)?(a):(b)
    #define Min(a,b) (a)<(b)?(a):(b)
    #define lson (step<<1)
    #define rson (lson+1)
    #define esp 1e-6
    #define oo 0x3fffffff
    #define TEST cout<<"*************************"<<endl
    
    using namespace std;
    typedef long long ll;
    
    int n;
    const int maxn=100000+10;
    ll d[maxn];
    ll p[maxn];
    ll ans;
    void test(int l,int r)//输出排序过程,检验正确与否
    {
        printf("l->%d r->%d
    ",l,r);
        for(int i=l;i<=r;i++)
            printf("%d ",d[i]);
        cout<<endl;
    }
    void merge_sort(int l,int r)//因为每一次排序只与l--r这段有关,所以可以把这段的排序结果放在p数组里,排完后再复制回原数组
    {
        if(l<r)
        {
            int mid=(l+r)>>1;
            merge_sort(l,mid);
            merge_sort(mid+1,r);
            int x=l,y=mid+1;
            int cnt=0;
            while(x<=mid||y<=r)
            {
                if(y>r||(x<=mid&&d[x]<=d[y]))
                    p[cnt++]=d[x++];
                else
                {
                    p[cnt++]=d[y++];
                    ans+=(x-l);//每次排序左半边的下标比右半边小,所以只需要在每次放右半边的数时看看左半边已经排好了多少,相应的就知道有多少等级高但值比下标大值小的数有多少
                }
            }
            int temp=l;
            rep0(i,cnt)
                d[temp++]=p[i];
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(~sc(n))
        {
            rep1(i,n)
                scanf("%lld",&d[i]);
            ans=0;
            merge_sort(1,n);
            printf("%lld
    ",1ll*n*(n-1)/2-ans);
        }
        return 0;
    }

    树状数组也是求逆序数的好方法,每放一个数,就比他小的数有多少个,也就是等级比他大但数值比他小的数量

    /**************************************************************
        Problem:hiho 1141
        User: youmi
        Language: C++
        Result: Accepted
        Time:151ms
        Memory:6M
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define scs(a) scanf("%s",a)
    #define sclld(a) scanf("%I64d",&a)
    #define pt(a) printf("%d
    ",a)
    #define ptlld(a) printf("%I64d
    ",a)
    #define rep0(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define rep_1(i,n) for(int i=n;i>=1;i--)
    #define rep_0(i,n) for(int i=n-1;i>=0;i--)
    #define Max(a,b) (a)>(b)?(a):(b)
    #define Min(a,b) (a)<(b)?(a):(b)
    #define lson (step<<1)
    #define rson (lson+1)
    #define esp 1e-6
    #define oo 0x3fffffff
    #define TEST cout<<"*************************"<<endl
    
    using namespace std;
    typedef long long ll;
    
    int n;
    
    const int maxn=100000+10;
    int b[maxn],c[maxn];
    struct node
    {
        int val,id;
        bool operator<(const node& a)const
        {
            return val<a.val;
        }
    }a[maxn];
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int x)
    {
        while(x<=n)
        {
            c[x]+=1;
            x+=lowbit(x);
        }
    }
    int query(int x)
    {
        int res=0;
        while(x>=1)
        {
            res+=c[x];
            x-=lowbit(x);
        }
        return res;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(~sc(n))
        {
            rep1(i,n)
            {
                sc(a[i].val);
                a[i].id=i;
            }
            sort(a+1,a+n+1);//下面为离散化过程,因为单个值太大,如果开相应大小的数组就爆栈了
            b[a[1].id]=1;
            for(int i=2;i<=n;i++)
            {
                if(a[i].val!=a[i-1].val)
                    b[a[i].id]=i;
                else
                    b[a[i].id]=b[a[i-1].id];
            }//以上为离散化过程
            /**<rep1(i,n)
                printf("%d ",b[i]);
            cout<<endl;  */
            zeros(c);
            ll ans=0;
            rep1(i,n)
            {
                ans+=query(b[i]);
                update(b[i]);
            }
            ll temp=1ll*n*(n-1)/2-ans;
            printf("%lld
    ",temp);
        }
        return 0;
    }
    不为失败找借口,只为成功找方法
  • 相关阅读:
    UVALive 7352 Dance Recital
    [ An Ac a Day ^_^ ] UVALive 7270 Osu! Master
    vim配置文件
    数据结构 链表
    [ An Ac a Day ^_^ ] hrbust 2291 Help C5 分形
    [ An Ac a Day ^_^ ] hdu 2553 N皇后问题 搜索
    [ An Ac a Day ^_^ ] HihoCoder 1249 Xiongnu's Land 线性扫描
    hdu 5874 Friends and Enemies icpc大连站网络赛 1007 数学
    hdu 5876 Sparse Graph icpc大连站网络赛 1009 补图最短路
    6.Z字变换 direction
  • 原文地址:https://www.cnblogs.com/youmi/p/4722815.html
Copyright © 2011-2022 走看看