Loading [MathJax]/extensions/tex2jax.js

「Codeforces 724F」Uniformly Branched Trees – 题解

主要思路

啊,又是无根树 DP。首先讨论奇偶性,如果是奇数的话可以直接 DP;如果不是,则需要容斥一波。

设置状态 \(dp[scale][maxPart][degree]\),意为大小为 \(scale\)、最大子树大小为 \(maxPart\) 且根度数为 \(degree\) 的方案树。转移其实很好想,看代码吧。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF724F.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010, MAX_D = 12;
int n, d, mod, inv[MAX_D], dp[MAX_N][MAX_N][MAX_D];
bool vis[MAX_N][MAX_N][MAX_D];
int fpow(int bas, int tim)
{
int ret = 1;
while (tim)
{
if (tim & 1)
ret = 1LL * ret * bas % mod;
bas = 1LL * bas * bas % mod;
tim >>= 1;
}
return ret;
}
int solve(int scale, int max_part, int cdeg)
{
if (vis[scale][max_part][cdeg])
return dp[scale][max_part][cdeg];
vis[scale][max_part][cdeg] = true;
int &ret = dp[scale][max_part][cdeg];
if (scale == 1)
return ret = (cdeg == 0);
if (cdeg == 0 || max_part == 0 || cdeg >= scale)
return ret = 0;
if (max_part == 1)
return ret = (scale == cdeg + 1);
ret = solve(scale, max_part - 1, cdeg);
int part = solve(max_part, max_part, d - 1);
if (part == 0)
return ret;
int binomial = 1;
for (int i = 1; i <= cdeg && 1LL * i * max_part <= scale - 1; i++)
{
binomial = 1LL * binomial * inv[i] % mod * (part + i - 1) % mod;
ret = (0LL + ret + 1LL * binomial * solve(scale - 1LL * i * max_part, max_part - 1, cdeg - i) % mod) % mod;
}
return ret;
}
int main()
{
scanf("%d%d%d", &n, &d, &mod);
for (int i = 1; i <= d; i++)
inv[i] = fpow(i, mod - 2);
if (n <= 2)
puts("1"), exit(0);
if (n & 1)
printf("%d\n", solve(n, n >> 1, d)), exit(0);
int part = solve(n >> 1, (n >> 1) - 1, d - 1);
part = 1LL * part * (part + 1) % mod * inv[2] % mod;
// printf("%d ", part);
part = (0LL + part + solve(n, (n >> 1) - 1, d)) % mod;
printf("%d\n", part);
return 0;
}
// CF724F.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1010, MAX_D = 12; int n, d, mod, inv[MAX_D], dp[MAX_N][MAX_N][MAX_D]; bool vis[MAX_N][MAX_N][MAX_D]; int fpow(int bas, int tim) { int ret = 1; while (tim) { if (tim & 1) ret = 1LL * ret * bas % mod; bas = 1LL * bas * bas % mod; tim >>= 1; } return ret; } int solve(int scale, int max_part, int cdeg) { if (vis[scale][max_part][cdeg]) return dp[scale][max_part][cdeg]; vis[scale][max_part][cdeg] = true; int &ret = dp[scale][max_part][cdeg]; if (scale == 1) return ret = (cdeg == 0); if (cdeg == 0 || max_part == 0 || cdeg >= scale) return ret = 0; if (max_part == 1) return ret = (scale == cdeg + 1); ret = solve(scale, max_part - 1, cdeg); int part = solve(max_part, max_part, d - 1); if (part == 0) return ret; int binomial = 1; for (int i = 1; i <= cdeg && 1LL * i * max_part <= scale - 1; i++) { binomial = 1LL * binomial * inv[i] % mod * (part + i - 1) % mod; ret = (0LL + ret + 1LL * binomial * solve(scale - 1LL * i * max_part, max_part - 1, cdeg - i) % mod) % mod; } return ret; } int main() { scanf("%d%d%d", &n, &d, &mod); for (int i = 1; i <= d; i++) inv[i] = fpow(i, mod - 2); if (n <= 2) puts("1"), exit(0); if (n & 1) printf("%d\n", solve(n, n >> 1, d)), exit(0); int part = solve(n >> 1, (n >> 1) - 1, d - 1); part = 1LL * part * (part + 1) % mod * inv[2] % mod; // printf("%d ", part); part = (0LL + part + solve(n, (n >> 1) - 1, d)) % mod; printf("%d\n", part); return 0; }
// CF724F.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1010, MAX_D = 12;

int n, d, mod, inv[MAX_D], dp[MAX_N][MAX_N][MAX_D];
bool vis[MAX_N][MAX_N][MAX_D];

int fpow(int bas, int tim)
{
    int ret = 1;
    while (tim)
    {
        if (tim & 1)
            ret = 1LL * ret * bas % mod;
        bas = 1LL * bas * bas % mod;
        tim >>= 1;
    }
    return ret;
}

int solve(int scale, int max_part, int cdeg)
{
    if (vis[scale][max_part][cdeg])
        return dp[scale][max_part][cdeg];
    vis[scale][max_part][cdeg] = true;
    int &ret = dp[scale][max_part][cdeg];
    if (scale == 1)
        return ret = (cdeg == 0);
    if (cdeg == 0 || max_part == 0 || cdeg >= scale)
        return ret = 0;
    if (max_part == 1)
        return ret = (scale == cdeg + 1);
    ret = solve(scale, max_part - 1, cdeg);
    int part = solve(max_part, max_part, d - 1);
    if (part == 0)
        return ret;
    int binomial = 1;
    for (int i = 1; i <= cdeg && 1LL * i * max_part <= scale - 1; i++)
    {
        binomial = 1LL * binomial * inv[i] % mod * (part + i - 1) % mod;
        ret = (0LL + ret + 1LL * binomial * solve(scale - 1LL * i * max_part, max_part - 1, cdeg - i) % mod) % mod;
    }
    return ret;
}

int main()
{
    scanf("%d%d%d", &n, &d, &mod);
    for (int i = 1; i <= d; i++)
        inv[i] = fpow(i, mod - 2);
    if (n <= 2)
        puts("1"), exit(0);
    if (n & 1)
        printf("%d\n", solve(n, n >> 1, d)), exit(0);
    int part = solve(n >> 1, (n >> 1) - 1, d - 1);
    part = 1LL * part * (part + 1) % mod * inv[2] % mod;
    // printf("%d ", part);
    part = (0LL + part + solve(n, (n >> 1) - 1, d)) % mod;
    printf("%d\n", part);
    return 0;
}

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *