• [CF1379E]Inverse Genealogy


    题目

    点这里看题目。

    分析

    对于这种构造题目,我们首先考虑边界情况。比如,我们可以计算不平衡点的上界,并且找到对应的构造方案,然后构造出来。

    这个上界可以如下构造:

              o
             / 
            o   o
           / 
          o   o
         /
       ...
       /
      o
     / 
    o   o
    

    也就是,首先构造一条链,长度为 (frac{n+1}{2}) (显然,有解的 (n) 一定是奇数)。接着,我们给链上的除任一端点以外的所有点加上一个儿子。这样我们就可以得到一棵有 (frac{n-3}{2}) 个不平衡点的树。可以发现这就是构造的上界。

    现在,我们称 (T_k) 为长成这个样子的树:

              1
             / 
            2   o
           / 
          3   o
         / 
       ...  o
       /
      k
       
        o
    

    此时只要节点 (k) 的左儿子大小大于 1 ,我们就可以获得 (k) 个不平衡点的贡献(否则也会有 (k-1) 个的贡献)。可以发现我们刚刚构造的上界就是这样构造出来的。

    接着考虑不平衡点的下界。显然,如果 (n=2^k-1(k>0)) ,那么它就可以构造出没有不平衡点的树。否则,最少只能构造出有一个不平衡点的树。这两种情况的构造方法是一样的,都是构造成完全二叉树的样子。

    将两个极端结合起来——如果 (k<2) ,我们可以判断并构造。否则,我们可以首先构造出 (T_{k-1}) 。然后构造出带来 1 的贡献的树,并且接到 (T_{k-1}) 下面去。

    如果 (n-2(k-1)) 不能构成满二叉树,我们就可以直接构造成完全二叉树并且接到 (T_{k-1}) 下面去。

    否则,考虑丢掉满二叉树的几个点,使得它不满,然后接到 (T_{k-1}) 下面。接着,我们只需要给提出来的点找位置就好了。

    不难想到构造 (n-2) 大小的树,接到 (T_{k-1}) 下面,然后将 2 个点接到 1 的右儿子上。此时,只要 1 的左儿子足够大, 1 还是可以贡献一个不平衡点。

    这样的构造方法只会有一个反例:n=9,k=2 。而经过枚举可以发现它是真的无解。
    于是问题就解决了,时间复杂度是 (O(n))

    小结:

    1. 有数量限制的构造题中,考虑数量的上下界是有用的思考方向。虽然可能跟最终构造方法没有关系,但是可以给你提供构造方法与思考方向。

    代码

    #include <cstdio>
    
    const int MAXN = 1e5 + 5, MAXLOG = 50;
    
    template<typename _T>
    void read( _T &x )
    {
        x = 0;char s = getchar();int f = 1;
        while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
        while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
        x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
        if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
        if( 9 < x ){ write( x / 10 ); }
        putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    void swapp( _T &x, _T &y )
    {
        _T t = x; x = y, y = t;
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b )
    {
        return a < b ? a : b;
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
        return a > b ? a : b;
    }
    
    int ance[MAXN];
    int N, M, K;
    
    int Lowbit( const int x ) { return x & ( -x ); }
    bool Chk( int x ) { return x - Lowbit( x ) == 0; }
    
    int main()
    {
        read( N ), read( K );
        int lim = MAX( ( N - 3 ) / 2, 0 );
        if( K > lim ) return puts( "NO" ), 0;
        if( N % 2 == 0 ) return puts( "NO" ), 0;
        if( N == 9 && K == 2 ) return puts( "NO" ), 0;
        if( Chk( N + 1 ) && K == 1 ) return puts( "NO" ), 0;
        if( ! Chk( N + 1 ) && K == 0 ) return puts( "NO" ), 0;
        
        puts( "YES" );
        int base = 2 * MAX( 0, K - 1 ); 
        for( int i = 1 ; i < base ; i += 2 )
            ance[i + 1] = i, ance[i] = MAX( 0, i - 2 );
        for( int i = 1 ; i <= N - base ; i ++ )
        {
            if( i == 1 ) ance[i + base] = MAX( 0, base - 1 );
            else ance[i + base] = ( i >> 1 ) + base;
        }   
        if( Chk( N - base + 1 ) && K ) ance[N - 1] = ance[N] = 2;
        for( int i = 1 ; i <= N ; i ++ ) write( ance[i] ), putchar( i == N ? '
    ' : ' ' );
        return 0;
    }
    
  • 相关阅读:
    Android app 简单的电话拨号器
    JavaWEB开发中的/到底代表什么
    springmvc json
    ForeignKey.on_delete
    django 实现指定文件合并成压缩文件下载
    常用SQL的优化
    数据库 两个简单实用的表级优化方法
    一天只能触发一次操作
    Ajax 生成流文件下载 以及复选框的实现
    django Q和F查询
  • 原文地址:https://www.cnblogs.com/crashed/p/13718889.html
Copyright © 2020-2023  润新知