• [CF1372E]Omkar and Last Floor


    题目

    点这里看题目。

    分析

    好妙的题!

    初看起来无从下手(我最初一直想着要分行依次叠加贡献),这样的话,我们不妨来看一下,第一步应该怎么计算贡献。

    面对区间 ([1,m]) ,一种方法是首先选出一列 (k),然后最大化这一列上的和——显然就是 (n) 。接着,所有经过了 (k) 的区间都不能再用了。那么问题自然地被划分成了 ([1,k-1])([k+1,m]) 两个独立的子问题。

    这提醒了我们,可以使用区间 DP 。可以考虑定义状态为:

    (f(i,j)) :左右端点都在 ([i,j]) 内的区间的最大贡献和。

    转移比较显然。记 (S(i,j,k)) 为所有的左右端点都在 ([i,j]) 中,且经过了 (k) 这个位置的区间数量。那么就有转移:

    [f(i,j)=max{f(i,k-1)+f(k+1,j)+(S(i,j,k))^2|ile kle j} ]

    这里的 (S) 理论上来说,可以直接 (O(n^3)) 地预处理出来(高位前缀和)。实际上直接 (O(n^4)) 也无伤大雅。

    总时间复杂度就是 (O(n^3)sim O(n^4))

    小结:

    本题的突破口就在于最初对于贡献计算的思考,所以如果最初没有思路,就可以先对问题进行一些基础的分析。

    代码

    #include <cstdio>
    
    const int INF = 0x3f3f3f3f;
    const int MAXN = 105;
    
    template<typename _T>
    void read( _T &x )
    {
        x = 0; char s = getchar(); int f = 1;
        while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
        while( '0' <= s && 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;
        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;
    }
    
    int f[MAXN][MAXN];
    int su[MAXN][MAXN][MAXN];
    
    int N, M;
    
    int main()
    {
        read( N ), read( M );
        for( int i = 1 ; i <= N ; i ++ )
        {
            int K, l, r;
            read( K );
            while( K -- )
            {
                read( l ), read( r );
                for( int a = 1 ; a <= l ; a ++ )
                    for( int b = r ; b <= M ; b ++ )
                        su[a][b][l] ++, su[a][b][r + 1] --;
            }
        }
        for( int i = 1 ; i <= M ; i ++ )
            for( int j = i + 1 ; j <= M ; j ++ )
                for( int k = i ; k <= j ; k ++ )
                    su[i][j][k] += su[i][j][k - 1];
        for( int i = M ; i ; i -- )
        {
            f[i][i + 1] = -INF;
            for( int j = i ; j <= M ; j ++ )
                for( int k = i ; k <= j ; k ++ )
                    f[i][j] = MAX( f[i][j], f[i][k - 1] + f[k + 1][j] + su[i][j][k] * su[i][j][k] );
        }
        write( f[1][M] ), putchar( '
    ' );
        return 0;
    }
    
  • 相关阅读:
    C#修饰符
    Exploring jQuery .live() and .die()
    ASP.NET Session丢失问题原因及解决方案
    5个 PHP 安全措施(转)
    jQuery方法click() bind() live() delegate()区别
    高性能网站的十四条黄金法则(雅虎14条)
    计算机科学概论读书笔记系列——绪论
    进程、线程、应用程序域、托管代码、元数据等。
    互联网协议入门(转)
    js跨域访问问题
  • 原文地址:https://www.cnblogs.com/crashed/p/13766487.html
Copyright © 2020-2023  润新知