COCI 2018/2019 Maja——暴力DP

目錄

一.題目

題目描述

輸入格式

輸出格式

樣例輸入

樣例輸出

二.題解

三.Code

謝謝!


神TM暴力DP能過!

一.題目

題目描述

Maja和蜜蜂在一片神奇的草地上爲花授粉,這塊草地可以表示爲一個n行m列的矩形,在第i行第j列中有CIJ朵沒有授粉的花。

Maja的蜂巢位於第a行第b列,她將從她的蜂巢開始爲這些花授粉,去草地上的某些塊授粉,然後再返回她的蜂巢。每次操作,Maja可以向相鄰的上下左右中的一個方格移動,而且她永遠不會離開草地。每次她經過的某塊草地,都會給這塊草地上所有未授粉的花授粉。但草地很神奇,一旦Maja離開草地(i,j),所有授粉的花都會消失,新的未授粉的花又會在這片土地上生長。

由於Maja不可能永遠飛行,她會在飛過k個格子後感到疲倦,並樂意向她的蜜蜂朋友們講述她的冒險故事。請問,在Maja授粉並在k步後返回蜂巢,她能授粉的花的數量是多少?

輸入格式

第一行包含正整數n,m(2≤n,m≤100),a(1≤a≤n),b(1≤b≤m)和k(2≤k≤1000000000),題目保證k是偶數

接下來n行,每行輸入m個數字,表示第i行第j列有未授粉的花Cij(0≤Cij≤1000000000)朵。

題目保證在蜂巢的位置不會有任何花。

輸出格式

輸出一個數,表示Maja最多能授粉的花的數量。

樣例輸入

3 3 2 2 6
5 1 0
1 0 3
1 3 3

樣例輸出

15

二.題解

看了第一眼,貌似只能暴力,再看走k步,好像可以用DP轉以上一步的狀態。

這裏有幾個結論:

1. 能授粉的花的數量的最大值一定是從你走出去的那一條路徑又原路返回

證明:你走出去的必定是你找到的能授粉的數量最多的一條路徑,當然原路返回最好。

2. 到了一個點後如果你不想再走了,但是如果現在直接回去會浪費步數,就直接走到旁邊權值最大的一個點,在這兩個點之間反覆走,一定是最優的。

證明:首先,k較大(k大於n*m)必然是在某個環上繞圈,否則沒地方走了。然後,在某個長度大於2的環上繞圈必然不會比在該環相鄰2個之和最大的兩個點之間來回走更優。證明:我們把環上的相鄰點兩兩分組,和最大的那組的平均值必然不小於總環的平均值。否則總和小於總和矛盾。

然後就直接DP轉移,dp[i][j][k]可以從相鄰的點的k-1步轉移過來。

這裏要優化一維,自己想。

三.Code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

#define LL long long
#define M 105
#define INF 0x7f7f7f7f

int n, m, a, b;
LL k, C[M][M], dp[M][M][2], ans;
int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

bool check (int x, int y){
    if (x < 1 || y < 1 || x > n || y > m)
        return 0;
    return 1;
}
int main (){
    scanf ("%d %d %d %d %lld", &n, &m, &a, &b, &k);
    for (register int i = 1; i <= n; i ++)
        for (register int j = 1; j <= m; j ++){
            scanf ("%lld", &C[i][j]);
            dp[i][j][0] = dp[i][j][1] = -INF;
        }
    k /= 2;
    LL step = min (k, 1ll * n * m);
    int tag = 0;
    dp[a][b][0] = 0;
    for (int i = 1; i <= step; i ++){
        tag ^= 1;
        for (int r = 1; r <= n; r ++){
            for (int c = 1; c <= m; c ++){
                LL Maxf = -INF, Maxc = -INF;
                for (register int j = 0; j < 4; j ++){
                    int tox = r + dir[j][0];
                    int toy = c + dir[j][1];
                    if (check (tox, toy)){
                        Maxf = max (Maxf, dp[tox][toy][(1 ^ tag)]);
                        Maxc = max (Maxc, C[tox][toy]);
                    }
                }
                if (Maxf == -INF)
                    continue;
                dp[r][c][tag] = Maxf + C[r][c];
                ans = max (ans, dp[r][c][tag] * 2 - C[r][c] + 1ll * (Maxc + C[r][c]) * (k - i));
            }
        }
    }
    printf ("%lld\n", ans);
    return 0;
}

謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章