BZOJ3769 SPOJ8549 BST again

什么鬼。

 

很好想的dp。f[i][j]表示深度不超过i且大小为j的二叉树的个数。转移是f[i][j] = ∑(f[i - 1][k] * f[i - 1][j - k - 1])。

 

然后直接暴力是O(n3)的。在spoj上能过在bzoj上不能过。在bzoj上得用记忆化搜索来减掉一些无用的东西。虽然我觉得很烦。

 

然后试图用fft,发现fft比暴力还慢。然后试图用fnt,然后发现fnt好像不能对1e9+7这种质数用。因为1e9+6只有来一个2。真悲伤。我还是太弱啊。

 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
 
using namespace std;
 
const int maxn = 609;
const int mod = 1000000007;
 
#define _l (long long int)
 
int f[maxn][maxn];
 
int getf(int i, int j) {
    if (i == 0)
        return j <= 1;
    else if (j == 0)
        return 1;
    else if (f[i][j] == -1) {
        f[i][j] = 0;
        for (int k = 0; k < j; ++ k)
            f[i][j] = (f[i][j] + _l getf(i - 1, k) * getf(i - 1, j - k - 1)) % mod;
    }
    return f[i][j];
}
 
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
 
    memset(f, -1, sizeof(f));
    int t, n, k, s;
    scanf("%d", &t);
    while (t --) {
        scanf("%d%d", &n, &k);
        if (!k)
            puts((n == 1) ? "1" : "0");
        else {
            s = getf(k, n) - getf(k - 1, n);
            if (s < 0)
                s += mod;
            printf("%d\n", s);
        }
    }
}