zoukankan      html  css  js  c++  java
  • 康托展开

    康托展开和逆康托展开

    康托展开和逆康托展开

    前言

    康托展开和逆康托展开是针对全排列问题的。

    全排列:对于一个长度为 $N$ 的数组 $a$ , 满足 $1≤ai≤N$ 并且 各个元素互不相同。

    数组顺序
    1 2 3 4 51
    1 2 3 5 42
    1 2 5 3 43

    原理

    康托展开的例子

    如果给一个$N=5$ 的数组$[3,2,5,4,1]$

    对于第一个数据3 , 后面比它小的数据有 2 个,所以 以 [1] 、[2] 为开头的全排列,都在它前面,$2*4!$

    对于第二个数据2 , 后面比它小的数据有 1 个,所以 以 [3,1] 为开头的全排列,都在它前面,$1*3!$

    对于第三个数据5,后面比它小的数据有 2 个,所以 以 [3,2,1]、[3,2,4] 开头的全排列,都在它前面,$2*2!$

    对于第四个数据4,后面比它小的数据有 1 个,所以 以 [3,2,5,1] 开头的全排列,都在它前面,$1*1!$

    对于第五个数据1,后面比它小的数据有 0 个,所以没有全排列在它前面,$0$

    $$ 2*4!+1*3!+2*2!+1*1!+0*0!+1 $$

    因为本身的顺序也算在其中,所以额外加1

    代码

    使用数状数组来进行统计 $ai$ 后面有多少比它小的元素。

    #include 
    #include 
    #include 
    using namespace std;
    typedef long long ll;
    const int mod = 998244353;
    const int MAXN = 1e6+5;
    ll fac[MAXN];
    ll node[MAXN];
    inline void Add(int i,int N){
        while(i<=N){
            node[i]-=1;
            i+=i&-i;
        }
    }
    inline ll Sum(int i){
        int s=0;
        while(i){
            s+=node[i];
            i-=i&(-i);
        }
        return s;
    }
    inline void Init(int N){
        ios::sync_with_stdio(false);
        cin.tie(0);
        fac[0]=1;
        memset(node,0,sizeof(node));
        for(ll i=1;i<=1e6;++i){
            fac[i]=(fac[i-1]*i)%mod;
            node[i]=i&-i;
        }
    }
    int main(){
        int N,x;
        ll sum=1;
        cin>>N;
        Init(N);
        for(int i=0;i>x;
            Add(x,N);
            sum+=Sum(x)*fac[N-i-1];
            sum%=mod;
        }
        cout<
    新赛季的开始
  • 相关阅读:
    xpath定向爬取
    正则表达式的零散知识
    正则表达式中的零宽断言
    Cookies
    一行代码从PDF提取Excel文件
    学习kafka的内容总结
    深度学习模型部署
    舆情情感分析
    关键词提取的几种常用方法总结以及代码实现
    语义预训练模型ERNIE
  • 原文地址:https://www.cnblogs.com/VagrantAC/p/12555040.html
Copyright © 2011-2022 走看看