• 「Gym103261H」Greedy Algorithm


    题目

    点这里看题目。

    分析

    首先我们可以发现行列是独立的,因此可以分开计算,因此以下以行为例讲解。

    \(H=\max_{i,j}h_{i,j}\)\(\delta_i\) 为第 \(i\) 行增加的高度。那么,如果第 \(i\) 行和第 \(i+1\) 行之间有贡献,则必然有 \(|\delta_i-\delta_{i+1}|\le H\);否则差值无论多少都可以。

    注意到,当差值无论多少都可以的时候,我们可以直接从那个位置破环为链。剩下的相邻行的差值可以任意选取,因此这是一个可以简单贪心的问题。

    考虑任意相邻行的差值绝对值都 \(\le H\) 的情况。这个时候必然满足差值的代数和为 0,可以 DP。如果暴力 DP 会得到 \(O(n^2H^2)\) 的算法,而注意到贡献可以和行分开,加入随机化即可将复杂度降到 \(O(nkH^2)\),其中 \(k\) 是一个较小的常数,用于限制转移的状态。

    小结:

    1. 思考的时候要更全面,“没有贡献时差值随意”没有想到,思维有点局限了。

    2. 多尝试几个方向,不要吊死在一种思路上。考试的时候只想到了“有一行的 \(\delta=0\)”,但是没有想到 \(\delta\) 差值的和为 0。使用前者解决问题会复杂得多,还是思考的时候太鲁莽了。

    代码

    #include <ctime>
    #include <cstdio>
    #include <random>
    #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 INF = 0x3f3f3f3f;
    const int MAXN = 55, MAXH = 505, MAXV = 25005;
    
    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 MAX( const _T a, const _T b ) {
        return a > b ? a : b;
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b ) {
        return a < b ? a : b;
    }
    
    int dp[2][MAXV << 1];
    
    int seq[MAXN];
    int row[MAXN][MAXH << 1], col[MAXN][MAXH << 1];
    
    int A[MAXN][MAXN];
    int N, M;
    
    inline void Upt( int &x, const int v ) { x = MAX( x, v ); }
    
    unsigned GetSeed() { char *tmp = new char; return time( 0 ) * ( unsigned long long ) tmp; }
    
    int main() {
        static std :: mt19937 rng( GetSeed() );
        int mxH = 0;
        read( N ), read( M );
        rep( i, 1, N ) rep( j, 1, M )
            read( A[i][j] ), mxH = MAX( mxH, A[i][j] );
        rep( i, 1, N ) {
            int j = i % N + 1;
            rep( k, - mxH, mxH ) rep( q, 1, M )
                row[j][k + mxH] += ( A[i][q] + k == A[j][q] );
        }
        rep( i, 1, M ) {
            int j = i % M + 1;
            rep( k, - mxH, mxH ) rep( q, 1, N )
                col[j][k + mxH] += ( A[q][i] + k == A[q][j] );
        }
        int rMx = 0, cMx = 0;
        int lim = 5 * mxH, pre, nxt, up, dn;
        rep( i, 1, N ) {
            int res = 0, tmp;
            rep( j, 1, N ) if( i ^ j ) {
                tmp = - INF;
                rep( k, - mxH, mxH )
                    tmp = MAX( tmp, row[j][k + mxH] );
                res += tmp;
            }
            rMx = MAX( rMx, res );
        }
    
        pre = 1, nxt = 0;
        rep( i, 1, N ) seq[i] = i;
        std :: shuffle( seq + 1, seq + 1 + N, rng );
        rep( j, - lim, lim ) dp[nxt][j + lim] = - INF; 
        dp[nxt][lim] = 0;
        rep( i, 1, N ) {
            pre ^= 1, nxt ^= 1;
            rep( j, - lim, lim )
                dp[nxt][j + lim] = - INF;
            rep( j, - lim, lim ) 
                if( dp[pre][j + lim] >= 0 ) {
                    up = MIN( lim, j + mxH );
                    dn = MAX( - lim, j - mxH );
                    rep( k, dn, up ) 
                        Upt( dp[nxt][k + lim], dp[pre][j + lim] + row[seq[i]][j - k + mxH] );
                }
        }
        rMx = MAX( rMx, dp[nxt][lim] );
        rep( i, 1, M ) {
            int res = 0, tmp;
            rep( j, 1, M ) if( i ^ j ) {
                tmp = - INF;
                rep( k, - mxH, mxH )
                    tmp = MAX( tmp, col[j][k + mxH] );
                res += tmp;
            }
            cMx = MAX( cMx, res );
        }
        
        pre = 1, nxt = 0;
        rep( i, 1, M ) seq[i] = i;
        std :: shuffle( seq + 1, seq + 1 + M, rng );
        rep( j, - lim, lim ) dp[nxt][j + lim] = - INF;
        dp[nxt][lim] = 0;
        rep( i, 1, M ) {
            pre ^= 1, nxt ^= 1;
            rep( j, - lim, lim )
                dp[nxt][j + lim] = - INF;
            rep( j, - lim, lim ) 
                if( dp[pre][j + lim] >= 0 ) {
                    up = MIN( lim, j + mxH );
                    dn = MAX( - lim, j - mxH );
                    rep( k, dn, up ) 
                        Upt( dp[nxt][k + lim], dp[pre][j + lim] + col[seq[i]][j - k + mxH] );
                }
        }
        cMx = MAX( cMx, dp[nxt][lim] );
        write( rMx + cMx ), putchar( '\n' );
        return 0;
    }
    
  • 相关阅读:
    C#中的委托,匿名方法和Lambda表达式
    模式化窗口问题![window.dialogArguments]
    js动态改变HiddenField值,后台不能获取值的问题
    将DataTable进行分页并生成新的DataTable
    出错提示为:该行已经属于另一个表 的解决方法
    如何在服务器端获得showModalDialog传递的参数
    Synchronized和SyncRoot与 集合类 的同步
    Oracle中数据出现####的问题
    如何防止多次提交按钮造成重复提交
    Invoke and BeginInvoke
  • 原文地址:https://www.cnblogs.com/crashed/p/15563174.html
Copyright © 2020-2023  润新知