这道题目在Timus上面的难度系数是165,可是当你做了之后就会发现,这道题目的难度系数大概也就七八十的样子,大概动态规划一类的问题都是这样吧,推导出了状态转移方程就没什么好说的,然而我并没有推导出状态转移方程,只是用了个记忆化搜索。
题目大意:用N个格子搭楼梯,每个阶梯之间严格递增,不允许相等的情况,至少要有两个阶梯,每个阶梯至少用一个格子,并没有对相邻阶梯的高度进行限制。问,有多少种搭建方法?
如果你是新手,或许很难去找到相应的问题模型来对这道题目进行套用,因为你可能真的像题目的描述那样,一步一步的去搭建。
但如果你以前就学过dp,并且也知道有数的划分这类型的问题,那么,稍加思考,这道题目就感觉so easy!
谈到数的划分,那就直接明了了吧,我相信,我们需要考虑的就是把一个数N划分为K(k > 1)个不相同的数,每个数要大于0,这样思路转换一下,就可以了。
枚举一下所有的可能,然后加上记忆化搜索,就完事儿了。下面还是照例献上自己丑陋的代码。
#include <iostream>
#include <cstring>
#define ll long long
using namespace std;
ll dp[501][501];
ll solve(int sum, int mx) {//由未知的k个不同的小于mx数来组成sum,事实上,我们并不需要知道k是多少
if (sum == 0) return 1;
if (dp[sum][mx] != -1) return dp[sum][mx];
ll ans = 0;
for (int i = min(mx - 1, sum); i >= 1; --i) {//sum - i 出现负数的情况
ans += solve(sum - i, i);
}
return dp[sum][mx] = ans;
}
int main() {
ll N;
cin >> N;
memset(dp, -1, sizeof dp);
ll ans = 0;
for (int i = N - 1; i >= 1; --i) {//i不能从N开始枚举,为了避免只有一个台阶的情况
ans += solve(N - i, i);
}
cout << ans << endl;
return 0;
}