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

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1770

这是这次BSG白山极客挑战赛B题。设p(i, j)表示节点个数为i,高度为jAVL树的个数。

那么,对于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的复杂度。显然是不行的。但是jk的范围是会被i约束的。于是我优化了j那一层,本地就能跑得很快了。设置了一个fromto表示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\n", ans);
    }
    return 0;
}
View Code

 

posted on 2016-05-24 16:10  AndyQsmart  阅读(728)  评论(0编辑  收藏  举报

导航