【题意】
我们知道1——k有K!种排列,现在给定k和n,要你按字典序输出 第n种排列的数列?
【解题方法】
BIT OR 线段树。(这段话是粘的别人的,懒的写,不过思路都一样)k最大为50000,直接算出来不可能,我发现这个n的表达式很有意思,明显(k-1)!就是表示第一次除第一个以外,剩下k-1个数的排列个数,乘一个S1就说明之前用了多少次这种排列了,根据这个 再手算了一下,发现就是,每次找第Sk个数,输出,当然已经访问过的数就要T出去
这很明显就是树状数组 (或者线段树的单点修改和查询)功能,先初始化每个都是大小为1,然后每次二分找第Sk个,找到之后,把该位置置为-1,消除该位的影响,继续找,继续输出即可。你看题目里给定的S的范围也就是顺应这个,故意把剩下几个数,S就恰好限定在这个里面。
【AC code】#include <bits/stdc++.h>
using namespace std;
const int maxn=50010;
int c[maxn];
int ans[maxn];
int n;
int lowbit(int x)
{
return (x&(-x));
}
void add(int x,int v)
{
while(x<=n){
c[x]+=v;
x+=lowbit(x);
}
}
int getsum(int x)
{
int ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1; i<=n; i++) add(i,1);
int val;
for(int i=1; i<=n; i++){
scanf("%d",&val);
int l=1,r=n;
while(l<r){
int mid=(l+r)/2;
int temp=getsum(mid);
if(temp<val+1) l=mid+1;
else r=mid;
}
add(l,-1);
ans[i]=l;
}
for(int i=1; i<n; i++) printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
}