洛谷P2525 Uim的情人节礼物·其之壱 [康托展开]

  题目传送门

Uim的情人节礼物·其之壱

题目描述

情人节到了,Uim打算给他的后宫们准备情人节礼物。UIm一共有N(1<=N<=9)个后宫妹子(现充去死 挫骨扬灰!)。

为了维护他的后宫的稳定。他通过编程,得出了一个送礼物的最佳顺序。这个我们管不着。

然而他认为,如果什么事情做得太圆满不是什么好事。于是他希望得到 原定顺序 的 前一个字典序的序列。

输入输出格式

输入格式:

第一行一个整数N

第二行N个整数,表示原定排列

 

输出格式:

前一个排列

 

输入输出样例

输入样例#1: 
3
1 3 2
输出样例#1: 
1 2 3

说明

若当前排列已经是第一个,则输出'ERROR'(引号不输出)


  分析:

  很多大佬都是用$STL$的$prev_permutation$做的,甚至有大佬搜索、模拟各种奇妙算法过。

  这里博主用的是康托展开和逆康托展开。

  非常容易,对于给定的排列,求出其康托展开值$m$,然后再求$m-1$的逆康托展开。

  Code:

//It is made by HolseLee on 8th Oct 2018
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int n,m,f[11],a[11];
char ka[11];
vector<int>v;

inline int cantor()
{
    int ret=0,x;
    for(int i=0; i<n; ++i) {
        x=0;
        for(int j=i+1; j<n; ++j)
        if( (ka[i]-ka[j])>0 ) x++;
        ret+=x*f[n-i-1];
    }
    return ret;
}

inline void incantor(int k)
{
    int x;
    while( !v.empty() ) v.erase(v.end());
    for(int i=1; i<=n; ++i) v.push_back(i);
    for(int i=1; i<n; ++i) {
        a[i]=v[(x=k/f[n-i])];
        v.erase(v.begin()+x);
        k%=f[n-i];
    }
    a[n]=v[0];
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=0; i<n; ++i) cin>>ka[i];
    f[1]=1;
    for(int i=2; i<=10; ++i) f[i]=f[i-1]*i;
    incantor(cantor()-1);
    for(int i=1; i<=n; ++i) printf("%d ",a[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cytus/p/9756022.html