• 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;
    }
    
  • 相关阅读:
    信息安全系统设计基础第一次实验报告
    信息安全系统设计基础第十二周学习总结
    信息安全系统设计基础第十一周学习报告
    信息安全系统设计基础第十周学习报告
    信息安全系统设计基础第九周学习总结
    Arduino智能小车实践学习报告
    信息安全系统设计基础期中总结
    信息安全系统设计基础第七周学习总结
    信息安全系统设计基础第六周学习总结
    信息安全系统设计基础第五周学习总结
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13767886.html
Copyright © 2020-2023  润新知