您的位置:首页 > 其它

vijos - P1092全排列 (康托展开 + 康托展开的逆运算)

2015-08-21 23:23 405 查看
P1092全排列
Accepted

标签:[显示标签]


描述

输入两个自然数m,n 1<=n<=20,1<=m<=n!

输出n个数的第m种全排列。
如 :

输入 3 1

输出 1 2 3


格式

输入格式

在一行中输入n m

输出格式

一个数列,既n个数的第m种排列

每两个数之间空1格


样例1

样例输入1[复制]

3 2


样例输出1[复制]

1 3 2



限制

各个测试点1s


来源

lk



给予一个目标排列,求解他的全排列过程中的第几个排列是通过康托展开:

找出45231在这个排列中的顺序

比4小的数有3个

比5小的数有4个但4已经在之前出现过了所以是3个

比2小的数有1个

比3小的数有两个但2已经在之前出现过了所以是1个

比1小的数有0个

那么45231在这个排列中的顺序是3*4!+3*3!+1*2!+1*1!+0*0!+1=94

如此,可以发现,所谓的第几个则是少于某个数的个数乘以阶乘。

给予一个原序列,以及一个数n代表着目标排列是全排列中的第几个排列,是通过康托展开的逆运算:

一个数量为5的排列,现在要你找出第96种排序序列是什么

首先用96-1得到95(将他本身这一个种给删掉,可以直接判断)

用95去除4! 得到3余23

用23去除3! 得到3余5

用5去除2!得到2余1

用1去除1!得到1余0

有3个数比它小的数是4

所以第一位是4

有3个数比它小的数是4但4已经在之前出现过了所以是5(因为4在之前出现过了所以实际比5小的数是3个)

有2个数比它小的数是3

有1个数比它小的数是2

最后一个数只能是1

所以这个数是45321

具体情况,请查看代码

#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <cctype>
using namespace std;

#define pb push_back
#define mp make_pair
#define fillchar(a, x) memset(a, x, sizeof(a))
#define copy(a, b) memcpy(a, b, sizeof(a))
#define S_queue<P> priority_queue<P, vector<P>,greater<P> >

typedef long long LL;
typedef pair<int, int > PII;
typedef unsigned long long uLL;
template<typename T>
void print(T* p, T* q, string Gap = " "){int d = p < q ? 1 : -1;while(p != q){cout << *p;p += d;if(p != q) cout << Gap; }cout << endl;}
template<typename T>
void print(const T &a, string bes = "") {int len = bes.length();if(len >= 2)cout << bes[0] << a << bes[1] << endl;else cout << a << endl;}

const int INF = 0x3f3f3f3f;
const int MAXM = 1e5;
const int MAXN = 1e4;
uLL F[21]={1,1,2,6,24,120,720,5040,40320,
362880,3628800,39916800,
479001600,6227020800,87178291200,
1307674368000,20922789888000,355687428096000,
6402373705728000,121645100408832000,2432902008176640000};
bool vis[30];
uLL Fig[25];
int main(){
uLL n, m, cnt;
cin >> n >> m;
m --;
for(uLL i = n - 1;i > 0;i --){
uLL k = m / F[i];
m %= F[i];
cnt = k + 1;
uLL xs = 1,ft = 0;
while(xs <= cnt){
ft ++;
if(!vis[ft]) xs ++;
}
vis[ft] = true;
cout << ft << " ";
}
for(int i = 1;i <= n;i ++){
if(!vis[i]) cout << i;
}
cout << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: