康托展开

题目链接

P5367 【模板】康托展开

【模板】康托展开

题目描述

\(1\sim N\) 的一个给定全排列在所有 \(1\sim N\) 全排列中的排名。结果对 998244353 取模。

输入格式

第一行一个正整数 \(N\)

第二行 \(N\) 个正整数,表示 \(1\sim N\) 的一种全排列。

输出格式

一行一个非负整数,表示答案对 998244353 取模的值。

输入 #1

3
2 1 3

输出 #1

3

输入 #2

4
1 2 4 3

输出 #2

2

说明/提示

对于\(10\%\)数据,\(1\le N\le 10\)

对于\(50\%\)数据,\(1\le N\le 5000\)

对于\(100\%\)数据,\(1\le N\le 1000000\)

解题思路

公式:

\[ans=1+∑_{i=1}^nA[i]×(n−i)! \]

其中\(A[i]\)代表\(\sum_{j=i}^{n}[a[j] < a[i]]\)
暴力解法:
时间复杂度:\(O(n^2)\)
树状数组优化:
时间复杂度:\(O(nlogn)\)

暴力代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,mod=998244353;
int n,a[N];
int res=1;
bool v[N];
int main()
{
    scanf("%lld",&n);
    for(int i=0;i<n;i++)scanf("%lld",&a[i]);
    for(int i=0;i<n;i++)
    {
        int cnt=0,fact=1;
        for(int j=1;j<=n-i-1;j++)fact=(1ll*fact*j)%mod;
        for(int j=1;j<a[i];j++)
            if(!v[j])cnt=(1ll*cnt+fact)%mod;
        v[a[i]]=true;
        res=(1ll*res+cnt)%mod;
    }
    printf("%lld",res);
    return 0;
}

优化代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,mod=998244353;
int n,a[N],fact[N];
int res=1;
int tr[N];
void add(int x,int y)
{
    for(;x<=n;x+=x&-x)tr[x]+=y;
}
int ask(int x)
{
    int res=0;
    for(;x;x-=x&-x)res+=tr[x];
    return res;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",&a[i]),add(i+1,1);
    fact[0]=1;
    for(int i=1;i<N;i++)fact[i]=(1ll*fact[i-1]*i)%mod;
    for(int i=0;i<n;i++)
    {
        res=(1ll*res+1ll*(ask(a[i])-1)*fact[n-i-1])%mod;
        add(a[i],-1);
    }
    printf("%d",res);
    return 0;
}

逆康托展开

题解链接

leetcode60. 排列序列

暴力时间复杂度:\(O(n^2)\)

暴力代码

class Solution {
public:
    string getPermutation(int n, int k) {
        //逆康托展开
        string res;
        vector<bool> v(10);
        for(int i=0;i<n;i++)
        {
            int cnt=1;
            for(int j=1;j<=n-i-1;j++)cnt*=j;
            for(int j=1;j<=n;j++)
                if(!v[j])
                {
                    if(cnt<k)k-=cnt;
                    else
                    {
                        res+=to_string(j);
                        v[j]=true;
                        break;
                    }
                }
        }
        return res;
    }
};

posted @ 2021-09-17 17:27  zyy2001  阅读(49)  评论(0编辑  收藏  举报