http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1770
这是这次BSG白山极客挑战赛的B题。设p(i, j)表示节点个数为i,高度为j的AVL树的个数。
那么,对于1 <= k <= i-1
p[i][j] += p[k][j-1]*p[i-1-k][j-1]%MOD;
p[i][j] += p[k][j-2]*p[i-1-k][j-1]%MOD;
p[i][j] += p[k][j-1]*p[i-1-k][j-2]%MOD;
但是这样模拟是n^3的复杂度。显然是不行的。但是j和k的范围是会被i约束的。于是我优化了j那一层,本地就能跑得很快了。设置了一个from和to表示j这一维跑的范围,那么每次这一次j的最小值就是下一次from,这一次j的最大值就是下一次的to。如此即可。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <string> #define LL long long #define MOD 1000000007 using namespace std; const int maxN = 2002; LL p[maxN][maxN]; void init() { int from, to, tfrom, tto; memset(p, 0, sizeof(p)); p[0][0] = 1; p[1][1] = 1; from = 0; to = 1; for (int i = 2; i < maxN; ++i) { tfrom = to; tto = from; to++; for (int j = from; j <= to; ++j) { for (int k = 0; k < i; ++k) { p[i][j] += p[k][j-1]*p[i-1-k][j-1]%MOD; if (j > 1) { p[i][j] += p[k][j-2]*p[i-1-k][j-1]%MOD; p[i][j] += p[k][j-1]*p[i-1-k][j-2]%MOD; } p[i][j] %= MOD; if (p[i][j]) { tfrom = min(tfrom, j); tto = max(tto, j); } } } from = tfrom; to = tto; } //cout << "OK"<<endl; } int main() { //freopen("test.in", "r", stdin); init(); int n; while (scanf("%d", &n) != EOF) { int ans; LL t = 0; for (int i = 1; i <= n; ++i) t = (t+p[n][i])%MOD; ans = t; printf("%d ", ans); } return 0; }