标签:
第1行:2个数N, K中间用空格分隔(1 <= N <= 100000, 0 <= K <= 10^9)。 第2至N + 1行:每行一个数i(1 <= i <= N)。
输出共N行,每行1个数,对应字典序最大的排列的元素。
5 6 1 2 3 4 5
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; }
标签:
原文地址:http://www.cnblogs.com/chen9510/p/5616129.html