Solution -「LOCAL」「cov. 牛客多校 2020 第三场 I」礼物

(mathcal{Description})

  给定排列 ({a_n}),求字典序第 (K) 大的合法排列 ({b_n})。称一个排列 ({p_n}) 合法,当且仅当依次将 ([1,m],[2,m+1],cdots,[n-m+1,n]) 内的 (p) 升序排列后,得到的排列为 ({a_n}) 相同。

  (nle2 imes 10^6)(mle 100)(Kle2 imes 10^{16})

(mathcal{Solution})

  应该说是构造题吧,想到几乎所有结论却打不出分 qwq。

  显然,(b_i)({a_n}) 中的下标属于集合 ([max{1,i-m+1},n]),反过来,(a_i)({b_n}) 中对应的下标属于集合 ([1,min{i+m-1,n}])

  然后可以发现 ({a_n}) 中的逆序对非常特殊。有性质:

[ (exists jin[1,i))(a_i<a_j) Rightarrow b_{i+m-1}=a_i ]

  归纳证明。考虑一对 ((i,j)),满足 (max_{kin(i,j)}{a_k}<a_j<a_i),若 (i+1=j),显然;否则对于 (kin(i,j)),已有 (b_{k+m-1}=a_k),不妨设 (b_x=a_j),则 (x otin[i+m,j+m-2]),而 (xin[1,min{j+m-1,n}]),又有 (xge i+m),所以 (x=j+m-1) 成立。

  所以可以直接确定所有存在逆序对的 (j) 的位置。接下来考虑 ({a_n}) 是一个单增排列的情况。

  从左往右构造 ({b_n}),我们需要求出固定 ({b_n}) 的前缀时所有合法 ({b_n}) 的方案数。不妨设固定前 (i) 位,对于一个没有出现的 (a_j),其放置方案数显然为 (min{j+m-1,n}-i)。乘法原理就可以得到所求,最后类似多叉树求第 (K) 大地枚举就好,复杂度 (mathcal O(n^3))

  由于方案数是指数增长,所以前面很多位直接从小到达钦定,再对后缀的 (mathcal O(log_mn)) 暴力构造即可。

  复杂度 (mathcal O(n+log^3n))

(mathcal{Code})

/* Clearink */

#include <cstdio>
#include <algorithm>

typedef long long LL;

inline LL rint () {
	LL x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
	return x;
}

template<typename Tp>
inline void wint ( Tp x ) {
	if ( x < 0 ) putchar ( '-' ), x = ~ x + 1;
	if ( 9 < x ) wint ( x / 10 );
	putchar ( x % 10 ^ '0' );
}

inline int min_ ( const int a, const int b ) { return a < b ? a : b; }

const int MAXN = 2e6;
int n, m, a[MAXN + 5];
LL K;
int top, stk[MAXN + 5], ans[MAXN + 5];
bool used[MAXN + 5];

inline void setnxt ( int& pos, const int x ) { for ( ; ans[pos]; ++ pos ); ans[pos] = x; }

int main () {
	freopen ( "gift.in", "r", stdin );
	freopen ( "gift.out", "w", stdout );
	n = rint (), m = rint (), K = rint ();
	for ( int i = 1; i <= n; ++ i ) a[i] = rint ();
	for ( int i = 1; i <= n; ++ i ) {
		if ( a[i] < a[stk[top]] ) ans[i + m - 1] = a[i];
		else stk[++ top] = i;
	}
	int mut = top, pos = 1;
	for ( LL all = 1; mut && all < K; -- mut ) {
		all *= min_ ( m, top - mut + 2 );
	}
	for ( int i = 1; i < mut; ++ i ) setnxt ( pos, a[stk[i]] );
	for ( int i = mut; i <= top; ++ i ) {
		for ( int j = mut; j <= top; ++ j ) {
			if ( used[j] ) continue;
			used[j] = true;
			LL all = 1;
			for ( int k = mut, pre = i; k <= top; ++ k ) {
				if ( !used[k] ) {
					all *= min_ ( top, k + m - 1 ) - pre ++;
				}
			}
			if ( all < K ) K -= all, used[j] = false;
			else { setnxt ( pos, a[stk[j]] ); break; }
		}
	}
	for ( int i = 1; i <= n; ++ i ) {
		wint ( ans[i] );
		putchar ( i ^ n ? ' ' : '
' );
	}
	return 0;
}
原文地址:https://www.cnblogs.com/rainybunny/p/13767886.html