51Node 1364--- 最大字典序排列(树状数组)

51Node  1364--- 最大字典序排列(树状数组)

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 关注
给出一个1至N的排列,允许你做不超过K次操作,每次操作可以将相邻的两个数交换,问能够得到的字典序最大的排列是什么?
例如:N = 5, {1 2 3 4 5},k = 6,在6次交换后,能够得到的字典序最大的排列为{5 3 1 2 4}。
Input
第1行:2个数N, K中间用空格分隔(1 <= N <= 100000, 0 <= K <= 10^9)。
第2至N + 1行:每行一个数i(1 <= i <= N)。
Output
输出共N行,每行1个数,对应字典序最大的排列的元素。
Input示例
5 6
1
2
3
4
5
Output示例
5
3
1
2
4
思路:先用a[]数组记录下输入的1~N的一个排列,并用p[]数组记录输入的排列中每个数的位置即:a[i]=x,p[x]==i;用树状数组c[]记录第i个位置的数距离前面要插入的距离,当第i个数移到前面后,后面的数移到前面要插入的距离减一,所以修改树状数组c[]的的值。注意:主要循环i:N~1,先将大的数往前移动,如果需要移动步数太多则跳过。

代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
int N;
int a[100005];
int b[100005];
int p[100005];
int c[100005];

int Lowbit(int t)
{
    return t&(t^(t-1));
}
int sum(int x)
{
    int sum=0;
    while(x>0)
    {
        sum+=c[x];
        x-=Lowbit(x);
    }
    return sum;
}
void adjust(int li,int t)
{
    while(li<=N)
    {
        c[li]+=t;
        li=li+Lowbit(li);
    }
}

int main()
{
    int K;
    while(scanf("%d%d",&N,&K)!=EOF)
    {
        memset(c,0,sizeof(c));
        for(int i=1;i<=N;i++)
        {
            int x;
            scanf("%d",&x);
            a[i]=x;
            p[x]=i;
            adjust(i,1);
        }
        int tot=1;
        for(int x=N;x>=1;x--)
        {
            if(a[p[x]]==0) continue;
            if(K<=0) break;
            int tmp=sum(p[x])-1;///因为前面已经有了tot-1个数,所以距离插入位置边近;
            if(tmp>K) continue;
            K-=tmp;
            b[tot++]=x;
            a[p[x]]=0;
            adjust(p[x],-1);
            if(tmp==0)///不能每次都跳到x=N,否则会超时;
            x=N;
        }
        for(int i=1;i<=N;i++)
        {
            if(a[i])
                b[tot++]=a[i];
        }
        for(int i=1;i<=N;i++)
            printf("%d\n",b[i]);
    }
    return 0;
}

 

 

posted @ 2016-06-25 12:10  茶飘香~  阅读(442)  评论(0编辑  收藏  举报