思路是枚举攒够后面需要的所有钱的点。然后前面的点都是只要钱够就走,钱不够就等。再用 DP 算出每个点走到 (N,N) 最少需要花的钱,以此得出需要攒多少钱才能直接走完。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int n;
ll p[85][85],r[85][85],d[85][85],dp1[85][85],rest[85][85],dp2[85][85],ans=1e18;
int main(){
scanf("%d",&n);
for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)p[i][j]=1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%lld",&p[i][j]);
for(int i=1;i<=n;i++)for(int j=1;j<n;j++)scanf("%lld",&r[i][j]);
for(int i=1;i<n;i++)for(int j=1;j<=n;j++)scanf("%lld",&d[i][j]);
memset(dp1,0x3f,sizeof(dp1));
dp1[1][1]=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
if(i==1 && j==1)continue;
ll x=dp1[i][j-1]+(max(0ll,r[i][j-1]-rest[i][j-1])+p[i][j-1]-1)/p[i][j-1];
ll y=dp1[i-1][j]+(max(0ll,d[i-1][j]-rest[i-1][j])+p[i-1][j]-1)/p[i-1][j];
ll rx=(max(0ll,r[i][j-1]-rest[i][j-1])+p[i][j-1]-1)/p[i][j-1]*p[i][j-1]-r[i][j-1]+rest[i][j-1];
ll ry=(max(0ll,d[i-1][j]-rest[i-1][j])+p[i-1][j]-1)/p[i-1][j]*p[i-1][j]-d[i-1][j]+rest[i-1][j];
dp1[i][j]=min(x,y)+1;
if(x<y)rest[i][j]=rx;
if(x>y)rest[i][j]=ry;
if(x==y)rest[i][j]=max(rx,ry);
}
memset(dp2,0x3f,sizeof(dp2));
dp2[n][n]=0;
for(int i=n;i;i--)for(int j=n;j;j--){
if(i==n && j==n)continue;
dp2[i][j]=min(dp2[i+1][j]+d[i][j],dp2[i][j+1]+r[i][j]);
}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
ans=min(ans,dp1[i][j]+(max(0ll,dp2[i][j]-rest[i][j])+p[i][j]-1)/p[i][j]+(n-i)+(n-j));
printf("%lld",ans);
return 0;
}