zoukankan      html  css  js  c++  java
  • 康托展开&逆康托展开学习笔记

    啊。。。好久没写了。。。可能是最后一篇学习笔记了吧

    题目大意:给定序列求其在全排列中的排名&&给定排名求排列。

    这就是康托展开&&逆康托展开要干的事了。下面依次介绍

    一、康托展开

    首先,知道它是干嘛的。

    就是给定一个全排列之中的序列,求其在整个全排列中的排名。

    给出式子:
    $k=sum_{i=1}^n(n-i)!sum_{j=i+1}^n(a_{k,i}>a_{k,j})$

    解释一下:考虑这个序列的第i位,对于这个序列,只有前i位都小于等于它,第i位一定小于它的所有序列才会在它前面,于是对每一位考虑组合,就是这个结果了。

    代码片:

    ll ktz(ll *a)
    {
        ll ans=0;
        for(ll i=1;i<=n;i++)
        {
            ll cnt=0;
            for(ll j=i+1;j<=n;j++)
            {
                if(a[i]>a[j])//对每一位考虑
                cnt++;
            }
            ans+=cnt*fac[n-i];
        }
        return ans+1;//因为求的是前有多少,所有排名+1
    }

    二、逆康托展开

    好了,那有了排名怎么求数组呢?

    由上述康托展开可得,要得到数组的每一位,就必须确定前面有多少比它大的。

    于是反过来,对每一位考虑可以由多少比它大的,也就是求上述式子中括号里的东西,然后一位一位还原,就成了原序列

    过程:首先,同上,-1

    然后对每一位,把序号除以对应的fac,确定一个没用过的数,作为当前的答案即可

    代码片:

    ll nkt(ll k)
    {
        k-=1;
        ll j; 
        memset(vis,0,sizeof(vis));
        for(ll i=1;i<=n;i++)
        {
            ll s=k/fac[n-i];
            for(j=1;j<=n;j++)
            {
                if(!vis[j])
                {
                    if(!s)
                    break;
                    s--;
                }
            }
            printf("%d ",j);
            vis[j]=1;
            k%=fac[n-i];
        }
        printf("
    ");
    }

    (完)

  • 相关阅读:
    FFmpeg(二) 解封装相关函数理解
    Android NDK(一) ndk-build构建工具进行NDK开发
    Android NDK(二) CMake构建工具进行NDK开发
    C++学习笔记二、头文件与源文件
    C++学习笔记一
    JNA的步骤、简单实例以及资料整理
    Java异常总结
    UML-类图
    排序六:希尔排序
    排序四:归并排序--分治法
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11701540.html
Copyright © 2011-2022 走看看