目录
神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;
}