1. 程式人生 > 實用技巧 >[nowcoder5668I]Sorting the Array

[nowcoder5668I]Sorting the Array

令$f(n,b,m)=a[1..n]$(這裡下標從1開始),考慮一些性質: 性質1.對於$\forall 1\le i\le n-m+1$,若$\exists 1\le j<i,a[j]>a[i]$,那麼有$b[i+m-1]=a[i]$,證明略 根據性質1,可以去除掉所有滿足條件的$i$,那麼$a$就滿足單調上升 性質2.對於$\forall 1\le i\le n$,都有$a[i]=f(j,b,j)[i]$,其中$j=\min(i+m-1,n)$(歸納法即可證) 根據性質2,容易發現$a_{i}$合法當且僅當其填在$b[1..j]$中,即$b$的方案數為$\prod_{i=1}^{n}\min(m,n-i+1)$ 找到1個最大的$x$滿足$\prod_{i=x}^{n}\min(m,n-i+1)\ge k$,那麼$\forall 1\le i<x$,直接將$a_{i}$填在b中最小的未被填過的位置即可,而由於$m\ge 2$,所以有$n-x\ge \log_{2}k$,即僅需要考慮後$\lceil \log_{2}k \rceil+1$個位置,那麼不斷列舉當前位置上的數並判斷:1.剩餘方案數是否不小於k;2.這個位置上的數是否有限制(即填完後要保證$a[i-m+1]$的已填過了) 考慮時間複雜度,由於是多組資料,那麼複雜度為$o(n\log_{2}^{\ 2}k)$,可以通過優化降為$o(n\log_{2}k)$
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 800005
 4 int t,n,m,x,a[N],b[N],id[N],vis[N],ans[N];
 5 long long k;
 6 int main(){
 7     scanf("%d",&t);
 8     while (t--){
 9         scanf("%d%d%lld",&n,&m,&k);
10         int s=0,nn=0;
11         for(int i=1;i<=n;i++)ans[i]=0
; 12 for(int i=1,j=1;i<=n;i++){ 13 scanf("%d",&x); 14 if (s>x)ans[i+m-1]=x; 15 else{ 16 s=a[++nn]=x; 17 while (ans[j])j++; 18 id[nn]=j++; 19 } 20 } 21 int las=nn; 22 long
long sum=1; 23 while (sum<k){ 24 las--; 25 sum*=min(nn-las+1,m); 26 } 27 for(int i=1;i<las;i++)ans[id[i]]=a[i]; 28 for(int i=las;i<=nn;i++){ 29 vis[i]=0; 30 b[i]=min(nn-i+1,m); 31 } 32 for(int i=las;i<=nn;i++)
33 for(int j=las;j<=nn;j++) 34 if (!vis[j]){ 35 sum=sum/(b[j]--); 36 if (k<=sum){ 37 vis[j]=1; 38 ans[id[i]]=a[j]; 39 break; 40 } 41 k-=sum; 42 sum*=b[j]; 43 } 44 for(int i=1;i<=n;i++)printf("%d ",ans[i]); 45 printf("\n"); 46 } 47 }
View Code