uva10755
题意是求最大子立方体的和
Sol
降维 + 二维前缀和。
即是对于某一维,比如x,我们把(y,z)的二维前缀和保存在x里面。
s[i][j][k] = s[i][j - 1][k] + s[i][j][k - 1] - s[i][j - 1][k - 1] + g[i][j][k];
也就是这一句。
然后整一个O(n5)的枚举,对x进行dp。(这样实际上也可以理解为用三维表示了一个立方体)
for (ll i = 0; i <= y; i++) for (ll j = i + 1; j <= y; j++) for (ll p = 0; p <= z; p++) for (ll q = p + 1; q <= z; q++) { memset(dp, 0, sizeof 0);//最坏的情况是一个都不选。 for (ll k = 1; k <= x; k++) { ll t = count(i, j, p, q, k); dp[k] = max(dp[k - 1] + t, t); ans = max(ans, dp[k]); } }
本题还有一个坑点,不要把inf开太小,对于最大数小于231的题目,inf要开到1e10。
因为这个WA,就太亏了。
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; const ll maxn = 25, inf = 1e10; ll t, x ,y, z; ll s[maxn][maxn][maxn], g[maxn][maxn][maxn], dp[maxn]; ll count(ll i, ll j, ll p, ll q, ll k) { return s[k][j][q] - s[k][i][q] - s[k][j][p] + s[k][i][p]; } void solve() { scanf("%lld%lld%lld", &x, &y, &z); memset(s, 0, sizeof s); for (ll i = 1; i <= x; i++) for (ll j = 1; j <= y; j++) for (ll k = 1; k <= z; k++) { scanf("%lld", &g[i][j][k]); s[i][j][k] = s[i][j - 1][k] + s[i][j][k - 1] - s[i][j - 1][k - 1] + g[i][j][k]; } ll ans = -inf; for (ll i = 0; i <= y; i++) for (ll j = i + 1; j <= y; j++) for (ll p = 0; p <= z; p++) for (ll q = p + 1; q <= z; q++) { memset(dp, 0, sizeof 0);//最坏的情况是一个都不选。 for (ll k = 1; k <= x; k++) { ll t = count(i, j, p, q, k); dp[k] = max(dp[k - 1] + t, t); ans = max(ans, dp[k]); } } printf("%lld\n", ans); if (t) printf("\n"); } int main() { // freopen("uva10755.in","r",stdin); scanf("%lld", &t); while (t--) solve(); return 0; }