[校内训练19_09_06]排序

题意

一个这样的算法:

int cnt=0;
for(int i=1;i<=n;++i)
{
    for(int j=i+1;j<=n;++j)
    {
        if(a[j]<a[i])
        swap(a[j],a[i]);
        ++cnt;
    }
}

现在你cnt和原始数组a,求cnt步数后a的结果。注意a是n排列。

$1 \leq n \leq 10^6,1 \leq cnt \leq \frac{n(n-1)}{2}$

思考

对于某个i,如果j从i+1循环到了n,那么含义就是将i~n中最小的数放到第i位上,剩下的访问过的向右循环位移一位(在访问过的数中循环位移)。

如果说外层的i在1~k中都完全遍历了一边,那么含义就是将1~k放到最前面。

如果我们从小到大依次插入数字i,可以发现,最后每个数字的相对位置是不会改变的。

这样,我们模拟这个过程。首先确定每个数的位置在哪,将大小位1~k的位置扔到大根对中。接下来从k+1枚举到n,若数字i的位置比堆顶靠后,那么这个数的位置就不会有变化(因为比它小的数都在它之前)。否则这个数最后就会到堆顶的位置(注意是从k+1枚举到n,从小到大),将对顶弹出,把数字i的位置加入。

最后将剩下的步数处理了。

复杂度$O(nlogn)$

代码

 1 // luogu-judger-enable-o2
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 typedef long long int ll;
 5 const int maxn=1E6+5;
 6 int n,a[maxn],b[maxn],where[maxn];
 7 ll cnt;
 8 void solve(int x)
 9 {
10     if(x==0)
11         return;
12     priority_queue<int>Q;
13     for(int i=1;i<=n;++i)
14         where[a[i]]=i;
15     for(int i=1;i<=x;++i)
16     {
17         b[i]=i;
18         Q.push(where[i]);
19     }
20     for(int i=x+1;i<=n;++i)
21     {
22         if(where[i]>Q.top())
23             b[where[i]]=i;
24         else
25         {
26             b[Q.top()]=i;
27             Q.pop();
28             Q.push(where[i]);
29         }
30     }
31     for(int i=1;i<=n;++i)
32         a[i]=b[i];
33 }
34 int main()
35 {
36 //    freopen("sort.in","r",stdin);
37 //    freopen("sort.out","w",stdout);
38     ios::sync_with_stdio(false);
39     cin>>n>>cnt;
40     for(int i=1;i<=n;++i)
41         cin>>a[i];
42     for(int i=1;i<=n;++i)
43     {
44         if(cnt<=n-i)
45         {
46             solve(i-1);
47             for(int j=i+1;j<=n;++j)
48             {
49                 if(a[j]<a[i])
50                     swap(a[j],a[i]);
51                 --cnt;
52                 if(cnt==0)
53                 {
54                     for(int k=1;k<=n;++k)
55                         cout<<a[k]<<" ";
56                     cout<<endl;
57                     return 0;
58                 }
59             }
60         }
61         else
62             cnt-=n-i;
63     }
64     return 0;
65 }
View Code

 

转载于:https://www.cnblogs.com/GreenDuck/p/11553819.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值