题目:
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最多能授粉的花的数量。
样例
样例输入1
2 2 1 1 2
0 1
2 10
样例输出1
2
样例输入2
2 2 1 1 4
0 5
5 10
样例输出2
20
样例输入3
3 3 2 2 6
5 1 0
1 0 3
1 3 3
样例输出3
15
思路:
最初始的DP很容易想,即dp[i][j][k]表示在k时间,从(a,b)走到(i,j)的最大值
但是我们发现dp的转移方程其实只跟k-1有关,也就是说k我们可以滚动
之后,我们知道路径中的一段一定是在两个点之间反复横跳,
也就是说最外层枚举的时间其实只用到min(k,n*m),因为路径最长就n*m
代码:
# include<bits/stdc++.h>
using namespace std;
long long f[105][105][2],c[105][105];
long long n,m,A,B,K,ans=-0x7f7f7f7f7fll;
long long get(long long a,long long b,long long c,long long d)
{
if(b>a)
a=b;
if(c>a)
a=c;
if(d>a)
a=d;
return a;
}
int main()
{
cin>>n>>m>>A>>B>>K;
K=K>>1;
for(int i=0;i<=n+1;i++)
for(int j=0;j<=m+1;j++)
c[i][j]=f[i][j][0]=f[i][j][1]=-0x7f7f7f7f7fll;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>c[i][j];
}
}
f[A][B][0]=0;
for(long long r=1;r<=min(K,n*m);r++)
{
long long now=r&1;
long long pst=now^1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
long long temp=get(f[i-1][j][pst],f[i+1][j][pst],f[i][j-1][pst],f[i][j+1][pst]);
f[i][j][now]=max(temp+c[i][j],-0x7f7f7f7f7fll);
if (f[i][j][now]<0)
continue;
long long d=f[i][j][now]+temp;
d+=(K-r)*(c[i][j]+get(c[i-1][j],c[i+1][j],c[i][j-1],c[i][j+1]));
ans=max(ans,d);
}
}
cout<<ans;
return 0;
}