UVA 11525 Permutation-不重複全排列的第n項-(康託展開)
阿新 • • 發佈:2019-01-23
康託展開的公式 :
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai為整數,並且0<=ai<i(1<=i<=n)
適用範圍:沒有重複元素的全排列
(k-1)!就是表示第一次除第一個以外,剩下k-1個數的排列個數,乘一個S1就說明之前用了多少次這種排列了,
所以對應的排列第一項應該是可選集的第(an+1)小的數
//D - Mike and Feet #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; #define inf 0x7fffffff #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 50000+50; int n,m; class tree { public: int sum[maxn<<2]; void PushUP(int rt) { sum[rt] = (sum[rt<<1]+sum[rt<<1|1]); } void build(int l,int r,int rt) { if (l == r) { sum[rt]=1; return ; } int m = (l + r) >> 1; build(lson); build(rson); PushUP(rt); } int query(int l,int r,int rt,int x) //rt是節點編號 { if (l==r) return l; int mid=(l+r)>>1; if (sum[rt<<1]>=x) return query(l,mid,rt<<1,x); else return query(mid+1,r,rt<<1|1,x-sum[rt<<1]); } void update(int l,int r,int rt,int x) { if (l==r&&r==x) { sum[rt]=0; return ; } int mid= (l+r)>>1; if (x<=mid) update(l,mid,rt<<1,x); if (x>mid) update(mid+1,r,rt<<1|1,x); PushUP(rt); } }; tree tp; int main() { int t; cin>>t; while(t--) { int n; cin>>n; tp.build(1,n,1); int x; for (int i=1; i<=n; i++) { scanf("%d",&x); int ret=tp.query(1,n,1,x+1); tp.update(1,n,1,ret); if (i>1 )printf(" "); printf("%d",ret); } printf("\n"); } return 0; }