UVA 11525 Permutation(树状数组)

来源:互联网 发布:淘宝老版本苹果版下载 编辑:程序博客网 时间:2024/05/05 23:36

题目意思是说  给你一个数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;}


0 0