题解:
定义dp[i][j]为走到(i,j)的最大收益。为了防止枚举因数,建议用当前状态更新未来状态。
转移方程略,自己yy吧。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,a[24][1004];
int dp[24][1004];
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline bool in(int x,int y) {
return x>0&&x<=n&&y>0&&y<=m;
}
int main() {
// freopen("hdu 2571.in","r",stdin);
int kase=read();
while (kase--) {
n=read(),m=read();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
a[i][j]=read();
memset(dp,-INF,sizeof(dp));
dp[1][1]=a[1][1];
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) {
if (i^1||j^1) dp[i][j]+=a[i][j];
if (in(i+1,j)) dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
if (in(i,j+1)) dp[i][j+1]=max(dp[i][j+1],dp[i][j]);
for (int k=j<<1;k<=m;k+=j) {
if (!in(i,k)) break;
dp[i][k]=max(dp[i][k],dp[i][j]);
}
}
printf("%d\n",dp[n][m]);
}
return 0;
}