CF2194E The Turtle Strikes Back
考虑枚举修改的位置,这样我们就需要解决在知道修改哪个数的基础上快速求出最大享受值。我们有两个策略:经过这个点或不经过这个点。对于这类走格子的问题,有一个经典结论,所有 \(x+y\) 相等的点 \((x,y)\) 恰好只会经过其中的一个。那么就很简单了。我们先预处理从 \((1,1)\) 到 \((x,y)\) 和从 \((x,y)\) 到 \((n,m)\) 的最大享受值。对于经过这个点的情况,直接算修改后的享受值。对于不经过的情况,预处理出所有 \(x+y\) 相等的点中经过 \((x,y)\) 享受值最大的两个。
\(code\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m;
ll mf[N],mmf[N];
inline void solve()
{
cin>>n>>m;
for (int i=1;i<=n+m;++i) mf[i]=mmf[i]=LLONG_MIN;
vector<vector<int>> a(n+1,vector<int>(m+1));
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
cin>>a[i][j];
}
}
vector<vector<ll>> fo(n+1,vector<ll>(m+1)),fn(n+1,vector<ll>(m+1));
fo[1][1]=a[1][1];
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
if (i==1&&j==1) continue;
if (i==1) fo[i][j]=fo[i][j-1]+a[i][j];
else if (j==1) fo[i][j]=fo[i-1][j]+a[i][j];
else
{
if (fo[i-1][j]>=fo[i][j-1]) fo[i][j]=fo[i-1][j]+a[i][j];
else if (fo[i-1][j]<fo[i][j-1]) fo[i][j]=fo[i][j-1]+a[i][j];
}
}
}
fn[n][m]=a[n][m];
for (int i=n;i>=1;--i)
{
for (int j=m;j>=1;--j)
{
if (i==n&&j==m) continue;
if (i==n) fn[i][j]=fn[i][j+1]+a[i][j];
else if (j==m) fn[i][j]=fn[i+1][j]+a[i][j];
else
{
if (fn[i+1][j]>=fn[i][j+1]) fn[i][j]=fn[i+1][j]+a[i][j];
else if (fn[i+1][j]<fn[i][j+1]) fn[i][j]=fn[i][j+1]+a[i][j];
}
}
}
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
mf[i+j]=max(mf[i+j],fo[i][j]+fn[i][j]-a[i][j]);
if (mf[i+j]>mmf[i+j]) swap(mf[i+j],mmf[i+j]);
}
}
ll ans=LLONG_MAX;
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
ll maxv=0;
if (fo[i][j]+fn[i][j]-a[i][j]==mmf[i+j]) maxv=mf[i+j];
else maxv=mmf[i+j];
ans=min(ans,max(fo[i][j]+fn[i][j]-a[i][j]*3ll,maxv));
}
}
cout<<ans<<endl;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while (T--) solve();
return 0;
}
浙公网安备 33010602011771号