链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4173
题解
按照格点进行
DP
D
P
,每条边归属于它的左端点
如果从右边走过来:
f[i][j]=max{f[i−1][k]+s[i][k−1]−s[i][j−1]}(t[j]+...+t[k]≤K,j≤k≤M+1)
f
[
i
]
[
j
]
=
m
a
x
{
f
[
i
−
1
]
[
k
]
+
s
[
i
]
[
k
−
1
]
−
s
[
i
]
[
j
−
1
]
}
(
t
[
j
]
+
.
.
.
+
t
[
k
]
≤
K
,
j
≤
k
≤
M
+
1
)
如果从左边走过来
f[i][j]=max{f[i−1][k]+s[i][j−1]−s[i][k−1]}(t[k]+...+t[j]≤K,1≤k≤j)
f
[
i
]
[
j
]
=
m
a
x
{
f
[
i
−
1
]
[
k
]
+
s
[
i
]
[
j
−
1
]
−
s
[
i
]
[
k
−
1
]
}
(
t
[
k
]
+
.
.
.
+
t
[
j
]
≤
K
,
1
≤
k
≤
j
)
维护一下
f[i−1][k]+s[i][k−1]
f
[
i
−
1
]
[
k
]
+
s
[
i
]
[
k
−
1
]
或
f[i−1][k]−s[i][k−1]
f
[
i
−
1
]
[
k
]
−
s
[
i
]
[
k
−
1
]
的最值
网上的人都用单调队列,当然可以,不过我用的
ST
S
T
表
时间复杂度:
单调队列
O(nm)
O
(
n
m
)
ST
S
T
表
O(nmlogm)
O
(
n
m
l
o
g
m
)
代码
//DP
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#define maxn 110
#define maxm 10010
#define maxk 14
#define cl(x,y) memset(x,y,sizeof(x))
#define ll long long
#define ll_inf (1ll<<60)
using namespace std;
ll f[maxn][maxm], s[maxn][maxm], N, M, K, st[maxm][maxk+5], w[maxn][maxm], t[maxn][maxm];
ll read(ll x=0)
{
char c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
return f*x;
}
bool init()
{
ll i, j;
N=read()+1, M=read(), K=read();
if(N==1 and M==0 and K==0)return 0;
for(i=1;i<=N;i++)for(j=1;j<=M;j++)w[i][j]=read();
for(i=1;i<=N;i++)for(j=1;j<=M;j++)t[i][j]=read();
for(i=1;i<=N;i++)for(j=1;j<=M;j++)s[i][j]=w[i][j]+s[i][j-1];
for(i=1;i<=N;i++)for(j=1;j<=M;j++)t[i][j]+=t[i][j-1];
return 1;
}
ll stmax(ll l, ll r)
{
ll k=log2(r-l+1);
return max(st[l][k],st[r-(1<<k)+1][k]);
}
void DP()
{
ll i, j, k, ans=-ll_inf, l, r, mid;
for(i=1;i<=N;i++)
{
for(j=1;j<=M+1;j++)st[j][0]=f[i-1][j]+s[i][j-1];
for(k=1;1<<k<=M+1;k++)for(j=1;j+(1<<k)-1<=M+1;j++)st[j][k]=max(st[j][k-1],st[j+(1<<k-1)][k-1]);
for(j=1;j<=M+1;j++)
{
l=j, r=M+1;
while(l<r)
{
mid=l+r+1>>1;
if(t[i][mid-1]-t[i][j-1]>K)r=mid-1;
else l=mid;
}
f[i][j]=stmax(j,l)-s[i][j-1];
}
for(j=1;j<=M+1;j++)st[j][0]=f[i-1][j]-s[i][j-1];
for(k=1;1<<k<=M+1;k++)for(j=1;j+(1<<k)-1<=M+1;j++)st[j][k]=max(st[j][k-1],st[j+(1<<k-1)][k-1]);
for(j=1;j<=M+1;j++)
{
l=1, r=j;
while(l<r)
{
mid=l+r>>1;
if(t[i][j-1]-t[i][mid-1]>K)l=mid+1;
else r=mid;
}
f[i][j]=max(f[i][j],stmax(l,j)+s[i][j-1]);
}
}
for(i=1;i<=M+1;i++)ans=max(ans,f[N][i]);
printf("%lld\n",ans);
}
int main()
{
while(init())DP();
return 0;
}