Description:

n<=12,m<=30
题解:
很容易想到一种一行一行的dp,我们觉得n太小了,想一列一列做,发现不行。
然后脑洞打开,直接斜着dp,发现就没有了。
Code:
#include<cstdio>
#include<cstring>
#define pp printf
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const int N = 31;
int n, m, mo, a2[14];
int a[N * N][2], a0, b[N * N][2], b0, x, y;
int o, m2;
ll f[2][1 << 13], g[2][1 << 13];
#define w(x, y) ((x) >> (y) & 1)
int zz(int k, int d) {
int nn = (x == n || y == 1) ? 0 : w(k, x) * a2[n];
if(w(k, x)) k -= a2[x];
if(w(k, n)) k -= a2[n];
if(d == 1) k += a2[x - 1];
if(d == 2) k += a2[x];
return k + nn;
}
int main() {
freopen("bear.in", "r", stdin);
freopen("bear.out", "w", stdout);
a2[0] = 1; fo(i, 1, 13) a2[i] = a2[i - 1] << 1;
scanf("%d %d %d", &n, &m, &mo);
fo(i, 1, n) a[++ a0][0] = i, a[a0][1] = 1;
fo(j, 2, m) a[++ a0][0] = n, a[a0][1] = j;
m2 = a2[n + 1] - 1;
f[o][0] = 1;
fo(i, 1, a0 - 1) {
b0 = 0;
x = a[i][0], y = a[i][1];
while(x > 0 && y <= m)
b[++ b0][0] = x, b[b0][1] = y, x --, y ++;
fd(j, b0, 1) {
memset(f[!o], 0, sizeof f[!o]);
memset(g[!o], 0, sizeof g[!o]);
x = b[j][0], y = b[j][1];
fo(k, 0, m2) if(f[o][k]) {
f[o][k] %= mo;
g[o][k] %= mo;
int z1 = w(k, n), z2 = y == m ? 1 : w(k, x - 1), z3 = x == n ? 1 : 0;
if(z1 || z2 && z3) {
int nk = zz(k, 0);
f[!o][nk] += f[o][k] * 2;
g[!o][nk] += g[o][k] * 2;
} else
if(z2 && !z3) {
int nk = zz(k, 2);
f[!o][nk] += f[o][k] * 2;
g[!o][nk] += (g[o][k] + f[o][k]) * 2;
} else
if(!z2 && z3) {
int nk = zz(k, 1);
f[!o][nk] += f[o][k] * 2;
g[!o][nk] += (g[o][k] + f[o][k]) * 2;
} else {
int nk = zz(k, 1);
f[!o][nk] += f[o][k];
g[!o][nk] += (g[o][k] + f[o][k]);
nk = zz(k, 2);
f[!o][nk] += f[o][k];
g[!o][nk] += (g[o][k] + f[o][k]);
}
}
o = !o;
}
memset(f[!o], 0, sizeof f[!o]);
memset(g[!o], 0, sizeof g[!o]);
x = a[i + 1][0], y = a[i + 1][1];
while(x > 0 && y <= m) x --, y ++;
int p = x;
fo(k, 0, m2) if(f[o][k]) {
int nk = k - w(k, p) * a2[p] + a2[n] * w(k, p);
f[!o][nk] += f[o][k];
g[!o][nk] += g[o][k];
}
o = !o;
}
ll ans = 0;
fo(k, 0, m2) ans = (ans + g[o][k]) % mo;
pp("%lld\n", ans * 2 % mo);
}
本文介绍了一种使用斜向动态规划(DP)方法解决一个关于熊的游戏的问题,该问题涉及在一个n行m列的网格中,熊从左上角到右下角的路径选择,路径上每格可能有障碍物。文章详细描述了如何通过斜向DP来优化传统的一行一行或一列一列的DP方法,从而显著减少计算复杂度。代码实现部分展示了具体的算法流程,包括状态转移方程和边界条件处理。

被折叠的 条评论
为什么被折叠?



