zoukankan      html  css  js  c++  java
  • 构造逆序对

    题意:给定n , m,求解由 1-n 组成的 字典序最小的 逆序数对为m的 数列

    方法一: 暴力递归求解

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,m;
    int a[(int)5e4+5];
    void dfs(int l,int r,int ans)
    {
        if(l==r){
            cout<<l<<' ';
            return ;
    }
    if(l>=r)return ;
        if(a[r-l+1]>=ans)
        {
            cout<<l<<' ';
            dfs(l+1,r,ans);
        }
        else
        {
            for(int j=l+1;j<=r;j++)
                if(a[j-l+1]+a[r-j+1]+j-l>=ans)
                {
                    ans-=(j-l);
                    dfs(l+1,j,ans-=min(ans,a[r-j+1]));
                    cout<<l<<' ';
                    dfs(j+1,r,min(ans,a[r-j+1]));
                    break;
                }
        }
    }
    int main ()
    {
        a[1]=0,a[2]=0;
        for(int i=3;i<=5e4;i++)
            a[i]=a[i-1]+i-2;
        cin>>n>>m;
        dfs(1,n,m);
        return 0;
    }

    时间复杂度较高;如果n-1位数字构成的最大逆序数目大于m就将1直接放入 第一位 ,依次进行递归

    如果将此为是数字按顺序放入后剩余的数字构成的逆序数对不能大于m则将此数往后边的位置进行枚举,找到最近的满足此条件的位置然后分为两段进行递归

    第二种方法:

    #include<iostream>
    
    using namespace std;
    
    typedef long long ll;
    int a[(int )1e5+5];
    int main ()
    {
        ll n,m;
        cin>>n>>m;
        ll l=1,r=n;
        for(int i=1;i<=n;i++)
        {
            int t=(n-i)*(n-i-1)/2;
            if(t>=m)
                a[l++]=i;
            else
                a[r--]=i,m-=(r-l+1);
        }
        for(int i=1;i<=n;i++)
            cout<<a[i]<<' ';
        return 0; 
    }

    通过手动模拟第一种解法:从最小值进行排序的时候,要不就按照顺序放要不就倒着放。

    另一种证明方法: 所能构成的逆序数对越少,字典序越小,所以放在最后一位,会使前边的数字 字典序最小。

  • 相关阅读:
    myeclipse-9.0安装svn客户端插件
    jquery中lhgdialog插件(一)
    Jquery之ShowLoading遮罩组件
    git 命令
    org.apache.ibatis.builder.IncompleteElementException: Could not find parameter map
    在线压缩图片网址
    如何在知网下载外文文献
    Linux 常见命令
    在VIM 里面编辑和保存
    vi a.sh ABCD
  • 原文地址:https://www.cnblogs.com/zwx7616/p/11402218.html
Copyright © 2011-2022 走看看