CSP-S 2024 第六次

A

排序之后只会选相邻的,直接 DP。

B

从前往后考虑每个数 ai 要不要删。

若不删 ai

  • ai0,则 ai 已经确定。
  • ai=0,则 ai 可取所有没出现过的数,以及 i 后最小的数(先删掉它再把 ai 赋成它)

若删掉 ai

  • ai+10,则 ai 会变成 ai+1
  • ai+1=0,则 ai+1 可取所有没出现过的数(删除操作给 ai 了,所以没法取 i+1 后最小的数),然后 ai 会变成 ai+1

若不删 ai 可以使 ai 更小就不删,否则就删掉。

确定删掉的数之后,把没出现过的数从小到大填到空位里即可。

C

先把边权为 0 的边缩起来。

钦定 P1 为根,则 i 的答案是 1 当且仅当 P 的前 i 个点形成的虚树恰有 i 个点。

用 set 维护虚树点集即可。

D

先设 gn,l,p 表示有 n 个点,最大深度为 l,有 p 个深度最大的点的无标号有根树个数。

可以用分组背包的形式转移,枚举 n,l,p,t,每次加 tgn,l,p 内的树,有 (gn,l,p+t1t) 种方案(可重集组合数)。

对于 k 是偶数,钦定直径中点为根,则最大深度为 k/2,每两个属于根的不同子树的、深度都为 k/2 的叶子可以产生一个直径。

再设 fn,p,d 表示有 n 个点,有 p 个深度为 k/2 的叶子,有 d 个直径的无标号有根树个数,

转移同理,枚举 n,p,t,每次加 t 个大小为 n,有 p 个深度为 k/2 的叶子的子树(通过 g 得到方案数)即可。

对于 k 是奇数,在直径中边上加一个点,钦定这个点为根,

则根恰有两个子树,直径个数为两个子树中深度为 k2 的叶子个数之积。

枚举两个子树的大小,深度为 k2 的叶子个数,统计答案即可。

顶针要代码,那就放一下代码:

#include <cstdio>
#include <cstring>
#define M 998244353
#define int long long
bool F;
int n, k, p, o, v[50], g[50][50][50], G[50][50];
int C(int n, int k)
{
    int q = 1;
    for (int i = n + k - 1; i >= n; --i)
        q = q * i % M;
    for (int i = 1; i <= k; ++i)
        q = q * v[i] % M;
    return q;
}
signed main()
{
    freopen("dia.in", "r", stdin);
    freopen("dia.out", "w", stdout);
    v[1] = 1;
    for (int i = 2; i <= 40; ++i)
        v[i] = (M - M / i) * v[M % i] % M;
    scanf("%lld%lld%lld", &n, &k, &p);
    if (k & 1)
        F = 1;
    k = k + 1 >> 1;
    g[1][1][1] = 1;
    for (int vn = 1; vn <= n; ++vn)
        for (int vl = 1; vl <= k; ++vl)
            for (int vp = 1; vp <= vn; ++vp)
                for (int un = n - vn; un >= 1; --un)
                    for (int ul = 1; ul <= k; ++ul)
                        for (int up = 1; up <= un; ++up)
                            for (int t = 1; un + vn * t <= n; ++t)
                            {
                                int _ = C(g[vn][vl][vp], t);
                                if (vl + 1 > ul)
                                    g[un + vn * t][vl + 1][vp * t] = (g[un + vn * t][vl + 1][vp * t] + g[un][ul][up] * _) % M;
                                else if (vl + 1 == ul)
                                    g[un + vn * t][ul][up + vp * t] = (g[un + vn * t][ul][up + vp * t] + g[un][ul][up] * _) % M;
                                else
                                    g[un + vn * t][ul][up] = (g[un + vn * t][ul][up] + g[un][ul][up] * _) % M;
                            }
    for (int vn = 1; vn <= n; ++vn)
        for (int vp = 1; vp <= vn; ++vp)
        {
            G[vn][vp] = (G[vn][vp] + g[vn][k][vp]) % M;
            for (int vl = 1; vl < k; ++vl)
                G[vn][0] = (G[vn][0] + g[vn][vl][vp]) % M;
        }
    if (!F)
    {
        int f[50][50][50];
        memset(f, 0, sizeof f);
        f[1][0][0] = 1;
        for (int vn = 1; vn <= n; ++vn)
            for (int vp = 0; vp <= vn; ++vp)
                for (int un = n - vn; un >= 1; --un)
                    for (int ud = 0; ud <= p; ++ud)
                        for (int up = 0; up <= un && ud + up * vp <= p; ++up)
                        {
                            int _d = ud + vp * up, _p = up + vp;
                            for (int t = 1; un + vn * t <= n && _p <= n && _d <= p; ++t, _d += vp * _p, _p += vp)
                            {
                                int _ = C(G[vn][vp], t);
                                f[un + vn * t][_p][_d] = (f[un + vn * t][_p][_d] + f[un][up][ud] * _) % M;
                            }
                        }
        int z = 0;
        for (int i = 0; i <= n; ++i)
            z = (z + f[n][i][p]) % M;
        printf("%lld", z);
    }
    else
    {
        int z = 0;
        for (int vn = 1; vn <= n; ++vn)
            for (int vp = 0; vp <= vn; ++vp)
                for (int un = 1; un <= n; ++un)
                    for (int up = 0; up <= un; ++up)
                        if (un + vn == n && up * vp == p)
                        {
                            int _z = z;
                            if (un == vn && up == vp)
                                z = (z + C(G[un][up], 2) * 2) % M;
                            else
                                z = (z + G[un][up] * G[vn][vp]) % M;
                        }
        printf("%lld", z * (M + 1 >> 1) % M);
    }
    return 0;
}
posted @   Jijidawang  阅读(146)  评论(7编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示