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<
    新赛季的开始
  • 相关阅读:
    grunt in webstorm
    10+ Best Responsive HTML5 AngularJS Templates
    响应式布局
    responsive grid
    responsive layout
    js event bubble and capturing
    Understanding Service Types
    To add private variable to this Javascript literal object
    Centering HTML elements larger than their parents
    java5 新特性
  • 原文地址:https://www.cnblogs.com/VagrantAC/p/12555040.html
Copyright © 2011-2022 走看看