【洛谷题解】AT_abc415_e 题解
典。
首先一眼二分对吧。
二分出来这个高桥的初始钱数之后,只需要跑一个最简单的 DP 就可以了。
具体来说的话就是定义 \(dp_{i,j}\) 表示当前到了 \((i,j)\) 这个格子,高桥可以拥有的最大剩余钱数是多少。算上捡钱也算上买食物。
然后从 \((i-1,j)\) 或者 \((i,j-1)\) 转移过来就成。转移式很显然,所以不贴了,具体的去代码里看吧。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 2e5+5;
const LL INF = 0x3f3f3f3f3f3f3f3f;
LL n,m,l,r,ans,p[2*N];
vector<LL> a[N],dp[N];
bool check(LL num){
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)dp[i][j]=-INF;
dp[1][1]=num+a[1][1]-p[2];if(dp[1][1]<0)return 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(i==1&&j==1)continue;
if(i>1&&dp[i-1][j]>=0)dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i][j]-p[i+j]);
if(j>1&&dp[i][j-1]>=0)dp[i][j]=max(dp[i][j],dp[i][j-1]+a[i][j]-p[i+j]);
}
return (dp[n][m]>=0);
}
int main(){
cin>>n>>m;for(int i=1;i<=n;i++)a[i].push_back(0);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;cin>>x;a[i].push_back(x);}
for(int i=2;i<=n+m;i++)cin>>p[i];
for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)dp[i].push_back(0);
l=0,r=2e14,ans=2e14;
while(l<=r){
LL mid=(l+r)/2;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans<<"\n";
return 0;
}

浙公网安备 33010602011771号