UVA_11525 樹狀數組的活用 二分

來源:互聯網
上載者:User

標籤:style   blog   color   os   for   io   

我們知道1——k有K!種排列,現在給定k和n,要你按字典序輸出 第n種排列的數列

而且題目給的 n是 n=S1(k-1)!+S2(k-2)!+...+Sk-1*1!+Sk*0!(0=<Si<=k-i),

k最大為50000,直接算出來不可能,我發現這個n的運算式很有意思,明顯(k-1)!就是表示第一次除第一個以外,剩下k-1個數的排列個數,乘一個S1就說明之前用了多少次這種排列了,根據這個 再手算了一下,發現就是,每次找第Sk個數,輸出,當然已經訪問過的數就要T出去

這很明顯就是樹狀數組 (或者線段樹的單點修改和查詢)功能,先初始化每個都是大小為1,然後每次二分找第Sk個,找到之後,把該位置置為-1,消除該位的影響,繼續找,繼續輸出即可。你看題目裡給定的S的範圍也就是順應這個,故意把剩下幾個數,S就恰好限定在這個裡面

發現自己二分寫的還不是很熟,一開始還搞了一下子,是用mid還是L做結果呢 最後在我的寫法裡被證明是用L做結果

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define N 50000+10using namespace std;int A[N];int n;int lowbit(int x){    return x&(-x);}void add(int x,int v){    while (x<=n){        A[x]+=v;        x+=lowbit(x);    }}void init(){    for (int i=1;i<=n;i++){        add(i,1);    }}int query(int x){    int ret=0;    while (x>0){        ret+=A[x];        x-=lowbit(x);    }    return ret;}int main(){    int t;    scanf("%d",&t);    while (t--)    {      scanf("%d",&n);      init();      for (int i=1;i<=n;i++){        int a;        scanf("%d",&a);        int L=1,R=n,mid;        while (L<R)        {            mid=(L+R)>>1;            int tmp=query(mid);            //if (tmp==a+1) break;            if (tmp<a+1) L=mid+1;            else R=mid;        }        //cout<<"@@"<<mid<<endl;        add(L,-1);        printf("%d",L);        if (i<n) putchar(‘ ‘);      }      puts("");    }    return 0;}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.