版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
cogs提交
对于正整数N,则1到N这N个数可以构成N!种排列,把这些排列按照字典序从小到大列出。
如N=3时,列出1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1六个排列。
现在,给你排列{Pi},请你计算它后面的第K个排列{Qi}。
注意:这N!个排列是循环的,例如3 1 2后面的第2个排列是1 2 3。
类别
数量
数据描述
1
3
1<=N<=10 1<=K<=100000
2
3
1<=N<=1000 1<=K<=100000
3
3
1<=N<=1000 1<=K<=10^18
4
1
1<=N<=100000 1<=K<=10^18
自然的想法是求康拓展开,直接加k后逆康拓展开,但是n太大了,康拓结果根本存不了。
但是k不大,其实20个数就有20!个排列,这很大了,所以我们取出后20个数,按大小映射成0,1,2,3...19,康拓逆康拓 再映射回来就行,前面的数不用变。
但有特殊情况,后面20个数本身排列就字典序大,+K后超过了n!,这时候把它变成最后的排列19,18....0.映射回来,可以用STL的 next_permutation求整个序列的下一个序列,之后再处理一下后20位就可以了。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=10;
typedef long long LL;
LL k,fac[30];
bool v[30];
int n,b[30],a[101000];
LL cantor(int *a,int n) {
LL tmp = 0;
for (int i = 0; i < n; i++) {
int k = 0;
for (int j = i+1; j < n; j++) if(a[j] < a[i]) k++;
tmp += fac[n-i-1]*k;
}
return tmp+1;
}
void Inv_cantor(int n,LL m) {
--m;
for (int i = 0; i < n; i++) v[i] = 0;
for (int i = n-1; ~i; i--) {
int k = m/fac[i],j; m %= fac[i];
for (j = 0; j < n && k; j++) if(!v[j]) k--;
while(v[j]) j++;
v[b[n-i-1] = j] = true;
}
for (int i = 0; i < n; i++) ++b[i];
}
int c[30];
void Get() {
for (int i = 0; i < 20; i++) c[i] = a[n-20+i];
sort(c,c+20);
for (int i = 0; i < 20; i++) b[i] = lower_bound(c,c+20,a[n-20+i])-c+1;
}
void Re_Get() {
for (int i = 0; i < 20; i++) a[n-20+i] = c[b[i]-1];
}
inline LL Mod(LL x,LL p) {return x%p ? x%p : p;}
int main(int argc, char const *argv[]) {
freopen("sortb.in","r",stdin); freopen("sortb.out","w",stdout);
scanf("%d%lld",&n,&k);
for (int i = 0; i < n; i++) scanf("%d",a+i);
fac[0] = 1;
for (int i = 1; i <= 20; i++) fac[i] = fac[i-1]*i;
if(n <= 20) {
Inv_cantor(n,Mod(cantor(a,n)+k,fac[n]));
for (int i = 0; i < n; i++) printf("%d ",b[i]);
} else {
Get();
LL nt = cantor(b,20);
while(nt+k > fac[20]) {
for (int i = 0; i < 20; i++) a[n-20+i] = c[19-i];
next_permutation(a,a+n);
k -= fac[20]-nt+1;
nt = 1; Get();
}
Inv_cantor(20,nt+k);
Re_Get();
for (int i = 0; i < n; i++) printf("%d ",a[i]);
}
return 0;
}