zoukankan      html  css  js  c++  java
  • ZYB's Premutation(树状数组+二分)

     

     

    分析:我们可以逆向考虑(因为正向的话由于第一位的逆序对数一定是0,算不出什么),对于第i个数,它使逆序对的数量增加了temp=num[i]-num[i-1],即区间【1,i-1】内比这个数大的有temp个,即它在i个数中从小到大排在(i-temp)个,那么找到这个数即可。

    对于答案序列来讲,他是一个全排列的一种情况,对于用过了的数肯定就不再使用了。那么接下来的任务就是在剩余的数中,挑取第i-(num【i】-num【i-1】)大的数,作为这个位子上的答案;

    那么这部分我们可以用树状数组+二分来完成任务。

    对于树状数组,我们初始化每个位子上的val都是1.表示每个数字都还没被用过。那么getsum(i)的操作,就是在查找【1,i】这些数字中还剩余多少个数。

    那么我们考虑二分这个最终位子pos,使得【1,pos】中剩余的数字为i-(num【i】- num【i-1】)个即可。

    那么很容易理解,ans【i】=pos;

    对应每一次找到一个答案之后,对应updata(pos,-1)归零即可,表示这个位子上的这个数字我们已经用过了。

    AC_Code:

     1 #include <iostream>
     2 #include <string>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <algorithm>
     6 using namespace std;
     7 typedef long long ll;
     8 #define lowbit(x) ((x)&(-x))
     9 #define rep(i,first,last) for(int i=first;i<=last;i++)
    10 #define dep(i,first,last) for(int i=first;i>=last;i--)
    11 const int maxn=5e4+10;
    12 const int inf=0x3f3f3f3f;
    13 
    14 int num[maxn],tree[maxn],ans[maxn],n;
    15 
    16 void updata(int i,int k){
    17     while( i<=n ){
    18         tree[i]+=k;
    19         i+=lowbit(i);
    20     }
    21 }
    22 
    23 int getsum(int i){
    24     int res=0;
    25     while( i>0 ){
    26         res+=tree[i];
    27         i-=lowbit(i);
    28     }
    29     return res;
    30 }
    31 
    32 int solve(int k){
    33     int ans=0;
    34     int l=1;
    35     int r=n;
    36     while( l<=r ){
    37         int mid=(l+r)>>1;
    38         if( getsum(mid)>=k ){
    39             ans=mid;
    40             r=mid-1;
    41         }
    42         else l=mid+1;
    43     }
    44     return ans;
    45 }
    46 
    47 int main()
    48 {
    49     int T;
    50     scanf("%d",&T);
    51     while( T-- ){
    52         memset(tree,0,sizeof(tree));
    53         scanf("%d",&n);
    54         rep(i,1,n){
    55             updata(i,1);
    56             scanf("%d",&num[i]);
    57         }
    58         dep(i,n,1){
    59             int temp=num[i]-num[i-1];
    60             temp=i-temp;
    61             ans[i]=solve(temp);
    62             updata(ans[i],-1);
    63         }
    64         rep(i,1,n-1){
    65             printf("%d ",ans[i]);
    66         }
    67         printf("%d
    ",ans[n]);
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    imagemagick 批量旋转图片 转为横版式
    visual studio 2008 编译 filezilla
    BackgroundWorker 类
    序列化
    打工才是最愚蠢的投资
    常用汇编指令缩写(方便记忆)
    PIC中档单片机汇编指令详解(1)
    Win8之自动登录
    PIC单片机汇编指令
    好文转载—程序员的禅修之路
  • 原文地址:https://www.cnblogs.com/wsy107316/p/12324389.html
Copyright © 2011-2022 走看看