標籤:acm 資料結構 樹狀數組 uva algorithm
題目意思是說 給你一個數k 然後有k個si 問你1--k 的第n個全排列是多少 注意是 1 2 3...k的全排列 不是si的
N=
由觀察得知(k-i)!就是k-i個數位全排列種數, 0=<Si<=k-i,所以顯然可知假設當i==1時從第(k-1)!*s1到第n個全排列都是由第S1+1個數字開始的數列,因為每(k-1)!次排列過後,下一個排列的第1個數字都要增大1(每隔(k-1)!次,這k-1個數字都排列過一遍了,下一次只能增大更前面一個,也就是第1個了)
比如對於數列{1,2,3,4},假設S1=2,當i==1的時候對於2*(4-1)!,從0到(4-1)!排列一定是1,x,x,x,從1*(4-1)!到2*(4-1)!排列一定是2,x,x,x,從2*(4-1)!到3*(4-1)!的排列一定是3,x,x,x所以我們就知道了S1等於2的話,第一個數字一定是3,這樣我們就計算出了第一數字。。即我們確定這個數列一定是3,x,x,x
所以這樣我們通過S1可以計算出第一個數字,S2計算出第二個數字直到求出結果。。簡單的說就是由S1我們在這K個數字中找到第S1+1大的數字放在第一位,然後用剩下的K-1個數字去排列剩下的全排列,同樣的在這剩下的K-1個數字中找到第S2+1大的數字放在最前面
然後就用樹狀數組求第Si+1大啦~ 這個就不細說了
code(比較醜陋,不要介意~):
#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>#define ufor(a,b,c) for(int a=b;a<c;a++)#define dfor(a,b,c) for(int a=b;a>c;a--)#define LL long long#define clr(arr,val) memset(arr,val,sizeof(arr))using namespace std;const int maxn=50005;int a[maxn];int c[maxn];int k;int lowbit(int x){ return x&(-x);}void add(int x,int val){ while(x<=k) { c[x]+=val; x+=lowbit(x); }}int sum(int x){ int num=0,ans=0; dfor(i,16,-1) { num+=(1<<i); if(num>=k || c[num]+ans >= x) num-=(1<<i); else ans+=c[num]; } return num+1;}int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--) { cin>>k; clr(c,0); ufor(i,1,k+1) add(i,1); int tmp; ufor(i,0,k) { cin>>tmp; tmp++; int ans=sum(tmp); cout<<ans; if(i!=k-1) cout<<" "; else cout<<"\n"; add(ans,-1); } } return 0;}