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

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

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;
}
时间: 2024-08-04 01:13:42

51Node 1364--- 最大字典序排列(树状数组)的相关文章

uva 11525排列(树状数组 + 二分)

 现在给定k和n,要你按字典序输出 第n种排列的数列 而且题目给的 n是 n=S1(k-1)!+S2(k-2)!+...+Sk-1*1!+Sk*0!(0=<Si<=k-i), 我们可以知道si表示i后面有多少个比a[i]小的数,这样一来首先想到的就是set,但是set不能顺序访问,所以可以用树状数组,初始时置1,消除后置0,然后二分来求和为si + 1的位置 代码如下: #include<cstdio> #include<cstring> #include<c

51nod 1364 最大字典序排列(线段树)

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行

HDOJ 5338 ZZX and Permutations 线段树+树状数组

[题意]: 给一个排列加上表示循环的括号,问如何让1到n的对应的字典序最大. 从1开始贪心每个数字可以往三个地方走,右边第一个,跳转到左边的某一个,和自己构成循环 对于走到右边第一个的情况,只要判断右边的那个有没有被占据就可以了,如果可以和右边的互换,那么需要在线段树中将右边的数置为0 跳转到左边的某一个,一个数如果跳转到左边的某一个则说明左边的那个是括号开头这个数是括号结尾,用一个线段树查询区间里的最大值,由于括号间是不能重叠的,所以需要用树状数组二分一下左边界.如果这个数是要跳转到左边的某个

UVA_11525 树状数组的活用 二分

我们知道1——k有K!种排列,现在给定k和n,要你按字典序输出 第n种排列的数列 而且题目给的 n是 n=S1(k-1)!+S2(k-2)!+...+Sk-1*1!+Sk*0!(0=<Si<=k-i), k最大为50000,直接算出来不可能,我发现这个n的表达式很有意思,明显(k-1)!就是表示第一次除第一个以外,剩下k-1个数的排列个数,乘一个S1就说明之前用了多少次这种排列了,根据这个 再手算了一下,发现就是,每次找第Sk个数,输出,当然已经访问过的数就要T出去 这很明显就是树状数组 (或

Permutation UVA - 11525(值域树状数组,树状数组区间第k大(离线),log方,log)

Permutation UVA - 11525 看康托展开 题目给出的式子(n=s[1]*(k-1)!+s[2]*(k-2)!+...+s[k]*0!)非常像逆康托展开(将n个数的所有排列按字典序排序,并将所有排列编号(从0开始),给出排列的编号得到对应排列)用到的式子.可以想到用逆康托展开的方法.但是需要一些变化: for(i=n;i>=1;i--) { s[i-1]+=s[i]/(n-i+1); s[i]%=(n-i+1); } 例如:n=3时,3=0*2!+0*1!+3*0!应该变为3=1

树状数组(下)

树状数组(下) 目录 树状数组(下) 应用 逆序对 康托展开 逆康托展开 RMQ问题树状数组解法 查询第k小 习题 Preprefix sum 在树状数组(上)中我提到了树状数组的基本操作与变式,现在来看看它的实际应用和一些题目. 应用 逆序对 设\(a\)为一个有\(n\)个数字的有序集(\(n>1\)),其中所有数字各不相同. 如果存在正整数\(i\),\(j\)使得\(1\leqslant i<j\leqslant n\)且\(a[i]>a[j]\), 则有序对\((a[i],a[

hdu1540 Tunnel Warfare 线段树/树状数组

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly con

第十四个目标(dp + 树状数组)

Problem 2236 第十四个目标 Accept: 17    Submit: 35 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 目暮警官.妃英里.阿笠博士等人接连遭到不明身份之人的暗算,柯南追踪伤害阿笠博士的凶手,根据几起案件现场留下的线索发现凶手按照扑克牌的顺序行凶.在经过一系列的推理后,柯南发现受害者的名字均包含扑克牌的数值,且扑克牌的大小是严格递增的,此外遇害者与毛利小五郎有关. 为了避免

POJ 2352 【树状数组】

题意: 给了很多星星的坐标,星星的特征值是不比他自己本身高而且不在它右边的星星数. 给定的输入数据是按照y升序排序的,y相同的情况下按照x排列,x和y都是介于0和32000之间的整数.每个坐标最多有一个星星. 思路: 这题给的输入数据很祥和,间接提示思路了. 用x作为树状数组的区间,然后按照输入的顺序不断查找在包括自己的位置以及左边的星星数. 细节是x可能是0,这是树状数组不能接受的,需要对输入的x数据进行加一操作. 从这题可以看出树状数组最直白的作用就是求从1开始到某个点的某个区间的数量. #