码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2020-02-17 23:51:27      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:rem   info   逆向   int   情况   while   get   接下来   std   

技术图片

 

 技术图片

 

 

分析:我们可以逆向考虑(因为正向的话由于第一位的逆序对数一定是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\n",ans[n]);
68     }
69     return 0;
70 }

 

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

标签:rem   info   逆向   int   情况   while   get   接下来   std   

原文地址:https://www.cnblogs.com/wsy107316/p/12324389.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!