[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 }