2016 UESTC Training for Dynamic Programming M - 柱爷抢银行欢庆5.1special 递推

来源:互联网 发布:涡扇15和f119数据对比 编辑:程序博客网 时间:2024/05/23 02:03

M - 柱爷抢银行欢庆5.1special

Time Limit: 1000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

柱爷抢银行的手段日益熟练。为了欢庆5.1,柱爷准备再花式抢一波银行。

title

喵蛤蛤城是一个大的矩形方阵,而这方阵是由NM个矩形方格组成,方阵中的每个格子都有一家银行,柱爷抢这家银行能得到aij的钱,

aij<0柱爷会损失aij的钱。

柱爷最近练成了飞天螺旋大草,所以他决定要抢的银行要形成kk阶顺时针螺旋状,其中k3 任意奇数。下面是k=3,5,7   的图形,

其中黑色方块是柱爷要抢钱的银行。

title

请问柱爷最多能抢多少钱?

Input

第一行两个数N,M

之后NN行每行M个数,表示aij 

数据保证:

  • 3N,M500

  • 1000aij1000  。

Output

输出一行一个数,即答案。

Sample input and output

Sample InputSample Output
6 50 0 0 0 01 1 1 1 10 0 0 0 11 1 1 0 11 0 0 0 11 1 1 1 1
17
3 31 1 11 0 01 1 1
6
6 6-3 2 0 1 5 -14 -1 2 -3 0 1-5 1 2 4 1 -20 -2 1 3 -1 23 1 4 -3 -2 0-1 2 -1 3 1 2
13

Hint

请注意柱爷不是临阵退缩的人,既然来了,就至少要选择一个格子!(尽管可能会亏钱)

Source

2016 UESTC Training for Dynamic Programming


My Solution

递推

k阶的图刚好是k+2阶的图的白色部分 - val[i][j];

所以刚好dp[i][j] = getsum(i, j, i+k-1, j+k-1) - dp[i+1][j+1] - val[i+1][j];  
//dp[i+1][j+1] 还是上一个k 的

其中getsum(i, j, i+k-1, j+k-1)可以从二阶前置和得到, d1 - d2 - d3 + d4;

复杂度 O(n^3)

第一次碰到二阶前缀和,随便贴一个我写的版嘿嘿

inline int getsum(int i, int j, int x, int y)
{
    return (sum[x][y] - sum[x][j-1] - sum[i-1][y] + sum[i-1][j-1]);
}

void read()
{
for(int i = 0; i <= M; i++) sum[0][i] = 0;
    for(int i = 1; i <= N; i++){
        s[0] = 0;//这个可以直接放外面
        for(int j = 1; j <= M; j++){
            scanf("%d", &val[i][j]);


            dp[i][j] = val[i][j];
            //预处理二阶前缀和
            s[j] = s[j-1] + val[i][j];
            sum[i][j] = sum[i-1][j] + s[j-1] + val[i][j];
            //printf("sum[%d][%d] = %d;", i, j, sum[i][j]);
        }
        //printf("\n");
    }
}

#include <iostream>#include <cstdio>using namespace std;const int maxn = 500 + 8;int val[maxn][maxn], dp[maxn][maxn], sum[maxn][maxn], s[maxn];inline int getsum(int i, int j, int x, int y){    return (sum[x][y] - sum[x][j-1] - sum[i-1][y] + sum[i-1][j-1]);}int main(){    #ifdef LOCAL    freopen("a.txt", "r", stdin);    #endif // LOCAL    int N, M, K;    scanf("%d%d", &N, &M);    for(int i = 0; i <= M; i++) sum[0][i] = 0;    for(int i = 1; i <= N; i++){        s[0] = 0;//这个可以直接放外面        for(int j = 1; j <= M; j++){            scanf("%d", &val[i][j]);            dp[i][j] = val[i][j];            //预处理二阶前缀和            s[j] = s[j-1] + val[i][j];            sum[i][j] = sum[i-1][j] + s[j-1] + val[i][j];            //printf("sum[%d][%d] = %d;", i, j, sum[i][j]);        }        //printf("\n");    }    K = min(N, M);    int ans = -7*1002; //如果全负数就选3阶了,最多7个 -1000    //k = 1 的时候 dp[i][j] 就是 val[i][j] 了 上面已经处理好了    for(int k = 3; k <= K; k += 2){        for(int i = 1; i + k - 1 <= N; i++){            for(int j = 1; j + k - 1 <= M; j++){                dp[i][j] = getsum(i, j, i+k-1, j+k-1) - dp[i+1][j+1] - val[i+1][j];  //dp[i+1][j+1] 还是上一个k 的                //cout<<dp[i][j]<<endl;                ans = max(ans, dp[i][j]);            }        }    }    printf("%d", ans);    return 0;}

Thank you!
                                                                                                                                               ------from ProLights




0 0
原创粉丝点击