「CF1119G」Get Ready for the Battle

题目

点这里看题目。

分析

3100 的构造题,已经很奇妙了......

题目要求我们先输出所需的最少轮数。这一部分其实具有一定的提示性,因为我们可以猜一个下界,然后看是否能够达到它。比如,一个很好猜的下界就是 \(t_{\min}=\lceil\frac{\sum hp}{n}\rceil\)

但事实是,如果没有很好的构造技巧,即使知道这个下界可以被构造出来也没有用。

我们可以先对这个下界进行一些简单的分析。我们称给令敌方总血量减少 \(n\) 的一步为“完美”的一步。如果要达到这个下界,就说明我们在前 \(t_{\min}-1\) 步中,每一步都必须是“完美”的。当 \(n\le m\) 的时候,这个要求很简单,我们只需要将每个组的大小都设置为 1 即可。

考虑 \(n>m\) 的时候。我们不妨再进行一些限制,例如我们要顺序攻击每一组敌军,并且要求在攻击前 \(m-1\) 组时,每一步都是“完美”的。此时,我们可以将\(m\) 组合并为一整组。那么前 \(m-1\) 组的每一条组间分界线必须和我方的某一条攻击组分界线重合。

也即,设 \(s_i=\sum_{k=1}^ihp_k\),则对于所有的 \(1\le i<m\),我们的构造攻击方案都满足存在一个攻击的前缀,它带来的伤害之和为 \(s_i\)。由于每一轮攻击伤害之和都是 \(n\),因此我们构造的分组方案中,需要存在一个和为 \(s_i\bmod n\) 的前缀。

注意到需要满足的前缀只有 \(m-1\) 个,因此我们可以对 \(s_i\bmod n\) 排序后,取它们的差分,将剩下的再单独分成一组。最后扫描敌军的血量并分配即可。

小结:

  1. 在有步数限制的构造中,猜一个下界、上界可以让我们构造的目标清晰很多,也可以明确方向,降低构造难度。

  2. 注重基础分析,转换观察的角度。如果想不到“前面很多步都必须是‘完美’的”这个基础结论,那么后面的问题就很困难。同时,如果没有将若干组合并成为一组来观察,那也不简单了。

代码

#include <cstdio>
#include <algorithm>

#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )

const int MAXN = 1e6 + 5;

template<typename _T>
void read( _T &x ) {
    x = 0; char s = getchar(); bool f = false;
    while( s < '0' || '9' < s ) { f = s == '-', s = getchar(); }
    while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
    if( f ) x = -x;
}

template<typename _T>
void write( _T x ) {
    if( x < 0 ) putchar( '-' ), x = -x;
    if( 9 < x ) write( x / 10 );
    putchar( x % 10 + '0' );
}

template<typename _T>
_T MIN( const _T a, const _T b ) {
    return a < b ? a : b;
}

int hp[MAXN];

int N, M;

namespace SmallN {
    int seq[MAXN], tot;

    void Solve() {
        rep( i, 1, N ) putchar( '1' ), putchar( ' ' );
        rep( i, N + 1, M ) putchar( '0' ), putchar( ' ' );
        puts( "" );
        rep( i, 1, M ) {
            int tims = hp[i] / N;
            rep( j, 1, tims ) {
                rep( k, 1, M )
                    write( i ), putchar( ' ' );
                puts( "" );
            }
            hp[i] %= N;
            rep( j, 1, hp[i] )
                seq[++ tot] = i;
        }
        for( int i = 1 ; i <= tot ; i += N ) {
            int lim = MIN( N, tot - i + 1 );
            rep( j, 1, lim ) write( seq[i + j - 1] ), putchar( ' ' );
            rep( j, lim + 1, M ) putchar( '1' ), putchar( ' ' );
            puts( "" );
        }
    }
}

namespace LargeN {
    int pref[MAXN], val[MAXN], tmp[MAXN], pos[MAXN], tot;  

    void Solve() {
        rep( i, 1, M ) pref[i] = pref[i - 1] + hp[i];
        rep( i, 1, M - 1 ) tmp[++ tot] = pref[i] % N;
        std :: sort( tmp + 1, tmp + 1 + tot );
        tot = std :: unique( tmp + 1, tmp + 1 + tot ) - tmp - 1;
        rep( i, 1, tot ) { 
            val[i] = tmp[i] - tmp[i - 1];
            pos[tmp[i]] = i;
        }
        val[tot + 1] = N - tmp[tot];
        rep( i, 1, M ) write( val[i] ), putchar( i == M ? '\n' : ' ' );
        for( int i = 1, j ; i < M ; ) {
            for( ; i < M && ! hp[i] ; i ++ );
            if( i == M ) break;
            int su = 0, lst = 0;
            for( j = i ; j < M && ( su += hp[j] ) <= N ; j ++ );
            for( int k = i ; k <= j ; k ++ ) {
                while( lst < M && hp[k] >= val[lst + 1] ) {
                    hp[k] -= val[++ lst];
                    write( k ), putchar( ' ' );
                }
                if( lst == M ) break;
            }
            for( int i = lst + 1 ; i <= M ; i ++ )
                hp[M] -= val[i], write( M ), putchar( ' ' );
            puts( "" );
        }
        if( hp[M] > 0 ) {
            int tims = ( hp[M] + N - 1 ) / N;
            rep( j, 1, tims ) {
                rep( k, 1, M )
                    write( M ), putchar( ' ' );
                puts( "" );
            }
        }
    }
}

int main() {
    int su = 0;
    read( N ), read( M );
    rep( i, 1, M ) read( hp[i] ), su += hp[i];
    printf( "%d\n", ( su + N - 1 ) / N );
    if( N <= M ) 
        SmallN :: Solve();
    else 
        LargeN :: Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/15556987.html