您的位置:首页 > 其它

ACM学习历程—51NOD 1412 AVL树的种类(递推)

2016-05-24 16:10 399 查看
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
[i])%MOD;
ans = t;
printf("%d\n", ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: