Lc今天上课学会了数的全排列并且Lc觉得数的全排列很简单,但是直到Lc的同桌YooQ向他提出了一个问题,该问题的描述如下:我们知道n的全排列总共有n!个序列,例如2的全排列有两个序列{1,2}和{2,1},现在你要解决的问题是n的全排列的n!个序列中第m个序列是什么?(注意:n的全排列的n!个序列是按字典序由小到大排序的)
输入格式:
第一行为样例组数t(t≤1e5),接下来t行每行有一个整数n和m(1<=n<=20,1<=m<=n!)
输出格式:
输出t行,每行输出n的全排列的n!个序列中第m个序列,两相邻的数间有一空格,行末不得有多余空格。
输入样例:
在这里给出一组输入。例如:
2
1 1
3 6
输出样例:
在这里给出相应的输出。例如:
1
3 2 1
思路:听别人说这道题直接用dfs的全排列会超时,所以我直接找的规律。
用数学打败数据结构
#include <bits/stdc++.h>
using namespace std;
const int N=22;
typedef unsigned long long int LL;
int st[N];
queue <int>q;
int main()
{
LL m;
int n;
int t;
LL a[N];
a[1]=1;
for(int i=2;i<=19;i++)
{
a[i]=a[i-1]*i;
}
int s[N];
scanf("%d",&t);
while(t--)
{
memset(st,0,sizeof(st));
scanf("%d %lld",&n,&m);
int k=n-1;
while(1)
{
int kk=(m-1)/a[k]+1;
int cnt=0;
for(int i=1;i<=n;i++)
{
if(st[i]==0)
{
cnt++;
}
if(cnt==kk)
{
q.push(i);
st[i]=1;
break;
}
}
k--;
if(q.size()==n)
break;
m-=(kk-1)*a[k+1];
}
int flag=1;
while(!q.empty())
{
if(flag==1)
{
printf("%d",q.front());
flag=0;
}
else printf(" %d",q.front());
q.pop();
}
printf("\n");
}
return 0;
}