zoukankan      html  css  js  c++  java
  • P2331 [SCOI2005]最大子矩阵

    $ color{#0066ff}{ 题目描述 }$

    这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。

    (color{#0066ff}{输入格式})

    第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

    (color{#0066ff}{输出格式})

    只有一行为k个子矩阵分值之和最大为多少。

    (color{#0066ff}{输入样例})

    3 2 2
    1 -3
    2 3
    -2 3
    

    (color{#0066ff}{输出样例})

    9
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{题解})

    蒟蒻太弱了。。蒟蒻什么都不会。。只会乱搞。。

    一看(mle2),显然乱搞啊

    Part one m=1

    这部分很好写把,直接(O(n^2k))DP就行了

    (f[i][k])表示前i个数,分成k段的最大值,可以预处理一个区间最大子段和转移就行

    具体可以看代码

    Part two m=2

    我写的可以说是及其恶心。。

    一下把两列理解为两个序列a,b

    刚开始,我只考虑到了3种情况,因为子矩阵只会有三种形态,a中的一段,b中的一段,a和b合一起大的一段

    然后可以预处理出a序列,b序列,ab合一起的序列的区间最大子段和,然后类似于Part One转移

    然而,情况并没有考虑全,但是可以拿到70pts

    还有什么情况呢??

    比如,我在a中选了([4,6])这一段,b中选了([5,7])这一段,然而DP中并不会允许两个同时选,因为这样DP会让其误以为重叠!!

    所以,蒟蒻想到一个办法,在设一个数组(p[i][j][k])代表从([i,j])选k段的答案

    这样转移的时候用p就方便多了

    p怎么预处理呢?? 其实就是n遍Part one

    然而。。。。90pts!!!

    蒟蒻冥思苦想,大力观察,发现居然还有一种可能!!

    比如在b中选了一个长度贼大的区间,在a中选了一大堆长度很小的区间,b这个大区间把这些小区间全部包含了,这种情况并没有转移到p!!

    蒟蒻再次冥思苦想,又开了两个数组(ff[i][j][k])表示在a中从i到j选k段的答案
    gg是在b中的,含义同ff

    这个还是类型Part one的DP,可以预处理

    更新(p[sta][i][l])的时候,可以用(p[sta][j - 1][l - num] + ff[j][i][r] + gg[j][i][num - r])

    然后终于把p弄完了,DP就行了。。

    复杂度O((n^3k^3 imes)极小常数)

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
        char ch; LL x = 0, f = 1;
        while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
        for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
        return x * f;
    }
    const int inf = 0x3f3f3f3f;
    const int maxn = 150;
    int n, m, k;
    namespace partone {
        int f[maxn][15], d[maxn][maxn], a[maxn];
        void predoit() {
            for(int i = 1; i <= n; i++) a[i] = in();
            for(int i = 1; i <= n; i++) {
                int ans = -inf, now = 0;
                for(int j = i; j <= n; j++) {
                    if(now + a[j] < 0) now = 0;
                    else now += a[j];
                    ans = std::max(ans, now);
                    d[i][j] = ans;
                }
            }
        }
        void DP() {
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= k; j++) f[i][j] = -inf;
                for(int j = 1; j <= i; j++)
                    for(int l = 1; l <= k; l++)
                        f[i][l] = std::max(f[i][l], f[j - 1][l - 1] + d[j][i]);
            }
            printf("%d
    ", f[n][k]);
        }
        int main() {
            predoit();
            DP();
            return 233;
        }
    }
    namespace parttwo {
     	int d[maxn][maxn][3], f[maxn][15], a[maxn], b[maxn], p[maxn][maxn][15];
     	int ff[maxn][maxn][15], gg[maxn][maxn][15];
     	void predoit() {
            for(int i = 1; i <= n; i++) a[i] = in(), b[i] = in();
            for(int i = 1; i <= n; i++) {
                int ans = -inf, now = 0;
                for(int j = i; j <= n; j++) {
                    if(now + a[j] < 0) now = 0;
                    else now += a[j];
                    ans = std::max(ans, now);
                    d[i][j][1] = ans;
                }
            }
            for(int i = 1; i <= n; i++) {
                int ans = -inf, now = 0;
                for(int j = i; j <= n; j++) {
                    if(now + b[j] < 0) now = 0;
                    else now += b[j];
                    ans = std::max(ans, now);
                    d[i][j][2] = ans;
                }
            }
            for(int i = 1; i <= n; i++) {
                int ans = -inf, now = 0;
                for(int j = i; j <= n; j++) {
                    if(now + a[j] + b[j] < 0) now = 0;
                    else now += a[j] + b[j];
                    ans = std::max(ans, now);
                    d[i][j][0] = ans;
                }
            }
            for(int sta = 1; sta <= n; sta++) {
                for(int i = sta; i <= n; i++) {
                    for(int j = 1; j <= k; j++) ff[sta][i][j] = gg[sta][i][j] = -inf;
                    for(int j = sta; j <= i; j++)
                        for(int l = 1; l <= k; l++) {
                            ff[sta][i][l] = std::max(ff[sta][i][l], ff[sta][j - 1][l - 1] + d[j][i][1]);
                            gg[sta][i][l] = std::max(gg[sta][i][l], gg[sta][j - 1][l - 1] + d[j][i][2]);
                        }
                    }
            }
            for(int sta = 1; sta <= n; sta++) {
                for(int i = sta; i <= n; i++) {
                    for(int j = 1; j <= k; j++) p[sta][i][j] = -inf;
                    for(int j = sta; j <= i; j++)
                        for(int l = 1; l <= k; l++) {
                            p[sta][i][l] = std::max(p[sta][i][l], p[sta][j - 1][l - 1] + d[j][i][1]);
                            p[sta][i][l] = std::max(p[sta][i][l], p[sta][j - 1][l - 1] + d[j][i][2]);
                            for(int num = 0; num <= l; num++)
                                for(int r = 0; r <= num; r++)
                                    p[sta][i][l] = std::max(p[sta][i][l], p[sta][j - 1][l - num] + ff[j][i][num - r] + gg[j][i][r]);
                        }
                }
            }
        }
        void DP() {
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= k; j++) f[i][j] = -inf;
                for(int j = 1; j <= i; j++)
                    for(int l = 1; l <= k; l++) {
                        f[i][l] = std::max(f[i][l], f[j - 1][l - 1] + d[j][i][0]);
                        for(int num = 0; num <= l; num++)
                            f[i][l] = std::max(f[i][l], f[j - 1][l - num] + p[j][i][num]);
                    }
            }
            printf("%d
    ", f[n][k]);
        }
     	int main() {
     		predoit();
     		DP();
     		return 520;
     	}
    }
    int main() {
        n = in(), m = in(), k = in();
        if(m == 1) partone::main();
        else parttwo::main();
        return 0;
    }
    
  • 相关阅读:
    【NOIP2009提高组T4】靶形数独-DFS剪枝+位运算优化
    【NOIP2009提高组T4】靶形数独-DFS剪枝+位运算优化
    【NOIP2011提高组T3】Mayan游戏-DFS剪枝
    【NOIP2011提高组T3】Mayan游戏-DFS剪枝
    【POJ1469】Courses-二分图最大匹配
    mong 备份和恢复
    Linux ldconfig 查看动态库连接
    Linux ldconfig 查看动态库连接
    zookeeper perl 版本需求
    zookeeper perl 版本需求
  • 原文地址:https://www.cnblogs.com/olinr/p/10617522.html
Copyright © 2011-2022 走看看