noi.ac #43 dp计数

(sol)
状态

[f_{i, dis_1, dis_2, dis_3, dis_4} ]

表示到了第 (i) 层,其中 (dis_{1}) 表示第一根柱子剩下的最靠上的横木到当前 (i) 层的距离,以此类推。
显然后四维的范围 ([0, h])
枚举这一层所留下的横木是在哪一个梯子上,对应的 (dis) 变为 (0), 如果 (dis)(h),说明已经断了,这种情况还是 (h), 其他的 (dis + 1) 如果已经是 (h) 则不变
时间复杂度 (O(nh^4))

由于每一层必定会存在一个横木,也就是必定会有一个梯子 (dis)(0)
所以了以减少以为的 (dis)
同时改为 (0/1) 记录这一个梯子是否能不断连接到当前行。

[f_{i, 0/1, dis_{2}, dis_{3}, dis_{4}} ]

表示到了 (i) 层,在这一层放横木的那个梯子是否能爬到当前层,(dis) 同理

时间复杂度 (O(nh^3))
滚动数组优化空间

(cod)

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
const int mod = 1e9 + 9;

int n, h;

int now, old;
int f[2][2][33][33][33];

#define nex(x) ((x) == h ? h :(x) + 1)

void MOD(int &x)  {
	if (x >= mod) x -= mod;
}

int main() {
	
	scanf("%d%d", &n, &h);
	
	old = 0, now = 1;
	f[old][1][0][0][0] = 1;
	
	int tmp;
	for (int i = 1; i <= n; i ++) {
		for (int j = 0; j <= 1; j ++)
			for (int x = 0; x <= h; x ++)
				for (int y = 0; y <= h; y ++)
					for (int z = 0; z <= h; z ++)
					if (tmp = f[old][j][x][y][z]) {
						MOD(f[now][j][nex(x)][nex(y)][nex(z)] += tmp);
						MOD(f[now][x < h][nex(y)][nex(z)][j == 1 ? 1 : h] += tmp);
						MOD(f[now][y < h][nex(x)][nex(z)][j == 1 ? 1 : h] += tmp);
						MOD(f[now][z < h][nex(x)][nex(y)][j == 1 ? 1 : h] += tmp);
						f[old][j][x][y][z] = 0;
					}
		swap(now, old);
	}
	
	int ans = 0;
	for (int j = 0; j <= 1; j ++)
		for (int x = 0; x <= h; x ++)
			for (int y = 0; y <= h; y ++)
				for (int z = 0; z <= h; z ++) 
				if (j == 1 || x < h || y < h || z < h)
					ans += f[old][j][x][y][z], MOD(ans);
	printf("%d", ans);
	return 0;
}

原文地址:https://www.cnblogs.com/shandongs1/p/9705384.html