ZYB's Premutation(树状数组+二分)

Posted wsy107316

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

以上是关于ZYB's Premutation(树状数组+二分)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5592 ZYB's Game 树状数组+二分

6051: KiKi's K-Number (树状数组)

6051: KiKi's K-Number (树状数组)

HDU - 2852 KiKi's K-Number(树状数组+二分)

hdu 6468 zyb的面试

北邮校赛 F. Gabriel's Pocket Money(树状数组)