首页 > 其他分享 >2022.10.3-C 旅伴

2022.10.3-C 旅伴

时间:2022-10-15 09:23:35浏览次数:63  
标签:子树 int ye rb mul 旅伴 2022.10 mod

题意:

有一棵大小为 \(n\) 的无标号无根树,其中有三种结点:红蓝黄。

红色结点的度数最多为 \(4\),蓝、黄结点的度数最多为 \(3\)。

黄色结点之间不能有直接连边。

问方案数,\(\bmod~998244353\),\(n\le10000\)。


思路:

无根树同构问题,一般是转化为以重心为根,然后按照有根树来做,这道题也是这样。

我们先考虑一个 \(O(n^3)\) 的 暴力解法,每次我们枚举根的度数和颜色,每个子树的大小。

然后我们发现,对于大小相同的子树,实际上方案数也是相同的,这就启发我们对子树的大小进行 DP。

我们令 \(f_{0/1/2,~i}\) 表示当根是红/蓝/黄,子树大小为 \(i\) 时,方案数是多少。

显然这很难直接转移,因此我们还要定义两个数组:

\(rb_{d,~i}\) 表示根的度数为 \(d=0/1/2/3/4\),子树大小为 \(i\) 的方案数,且此时根应为红色或蓝色(其实当 \(d=4\) 就特指根为红色)。

\(ye_{d,~i}\) 表示根的度数为 \(d=0/1/2/3\),子树大小为 \(i\) 的方案数,且此时根的颜色应为黄色。

假设此时我们处理到子树大小为 \(i\) 的情况,

首先我们先更新 \(f\) 数组:

\[f_{0,~i}=\sum_{d=0}^3 rb_{d,~i} \]

\[f_{1,~i}=\sum_{d=0}^2 rb_{d,~i} \]

\[f_{2,~i}=\sum_{d=0}^2 ye_{d,~i} \]

为什么 \(f\) 不能更新满呢?因为我们要用 \(f\) 去更新 \(rb,ye\),那么要求 \(f\) 里的方案数都至少能再连出一条边。

这时候我们已经计算完大小为 \(i\) 的不同子树的方案数,我们就可以去更新 \(rb,ye\) 数组:

我们以更新 \(rb\) 为例,假设要更新 \(rb_{j,z}\):

我们枚举选出 \(w\) 个大小为 \(i\) 的子树,方案数显然为 \(\begin{pmatrix} tot+w-1 \\ w \end{pmatrix}\)

其中 \(tot=f_{0,i}+f_{1,i}+f_{2,i}\)

那么就有转移:

\[f_{j,z}\leftarrow f_{j-w, z-i*w} \times \begin{pmatrix} tot+w-1 \\ w \end{pmatrix} \]

\(ye\) 数组的更新同理,不过要注意 \(tot=f_{0,i}+f_{1,i}\),因为黄色不能与黄色连边。

因为重心的子树的大小不超过 \(\lfloor \frac{n}{2} \rfloor\),因此我们的 \(f\) 只需要更新到 \(\lfloor \frac{n}{2} \rfloor\)。

最后我们用 \(rb_{d,n}\) 和 \(ye_{d,n}\) 来计算最终的答案。

但有一个细节:对于 \(n\) 为偶数的情况,可能会出现两个重心的情况(就是某一条边连接的两棵子树大小都为 \(\frac{n}{2}\)),这时候我们需要去重。

一些具体细节见代码。


代码

#include<bits/stdc++.h>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
inline int rd()
{
    int sign = 1, re = 0; char c = getchar();
    while(!isdigit(c)){if(c == '-') sign = -1; c = getchar();}
    while(isdigit(c)){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
namespace MOD
{
    int mod;
    inline int add(int a, int b) {return a + b >= mod ? a + b - mod : a + b;}
    inline int mul(int a, int b) {return 1ll * a * b % mod;}
    inline int sub(int a, int b) {return a - b < 0 ? a - b + mod : a - b;}
    inline int fast_pow(int a, int b = mod - 2)
    {
        int re = 1;
        while(b)
        {
            if(b & 1) re = mul(re, a);
            a = mul(a, a);
            b >>= 1;
        }
        return re;
    }
} using namespace MOD;
int n, f[3][3005], inv[5];
int rb[5][3005], ye[4][3005];
int C[5];
signed main()
{
    n = rd(), mod = rd();
    inv[1] = 1; FOR(i, 2, 4) inv[i] = mul(sub(mod, mod / i), inv[mod % i]);
    rb[0][1] = ye[0][1] = 1;
    FOR(i, 1, n >> 1)
    {
        FOR(j, 0, 2)
            f[0][i] = add(f[0][i], rb[j][i]),
            f[1][i] = add(f[1][i], rb[j][i]),
            f[2][i] = add(f[2][i], ye[j][i]);
        f[0][i] = add(f[0][i], rb[3][i]);
        // 更新 ye
        int tot = add(f[0][i], f[1][i]);
        C[1] = tot;
        FOR(j, 2, 3) C[j] = mul(C[j - 1], mul(tot + j - 1, inv[j]));
        ROF(j, 3, 1) ROF(z, n, i + 1) for(int w = 1, mx = z / i; w <= mx && w <= j; w++)
            ye[j][z] = add(ye[j][z], mul(ye[j - w][z - i * w], C[w]));
        // 更新 rb
        tot = add(tot, f[2][i]);
        C[1] = tot;
        FOR(j, 2, 4) C[j] = mul(C[j - 1], mul(tot + j - 1, inv[j]));
        ROF(j, 4, 1) ROF(z, n, i + 1) for(int w = 1, mx = z / i; w <= mx && w <= j; w++)
            rb[j][z] = add(rb[j][z], mul(rb[j - w][z - i * w], C[w]));
    }
    int ans = 0;
    FOR(i, 0, 3) ans = add(ans, add(mul(rb[i][n], 2), ye[i][n]));
    ans = add(ans, rb[4][n]);
    if(!(n & 1)) // 有两个重心时,需要去重
    {
        int t = add(f[0][n >> 1], f[1][n >> 1]);
        if(t & 1) t = add(mul(t, (t - 1) >> 1), mul(t, f[2][n >> 1]));
        else t = add(mul(t - 1, t >> 1), mul(t, f[2][n >> 1]));
        ans = sub(ans, t);
    }
    printf("%d", ans);
    return 0;
}

GJ 那里需要开火车头才能通过;

Luogu 原题的范围是 \(n\le 3000\) 的,大家可以到那里去提交一下。

标签:子树,int,ye,rb,mul,旅伴,2022.10,mod
From: https://www.cnblogs.com/zuytong/p/16793571.html

相关文章

  • 【闲话】2022.10.14
    今天的考试可算是寄大方了以及:已知T1时限6s,T2T3T4时限均为2s,且每道题都有100个数据点。现在有3页提交。请问Accoders什么时候会炸?真的有一说一,性能不如......
  • 2022.10.14
    今天是我写博客的第一天,首先最重要的就是团队,已经有380人啦,我们的公开赛依然在审核中,已经过去一周了还没有审核好,其次今天在学校里得知我下个星期就要跑1000米了,呜呜呜,而且......
  • 2022.10 杂题
    P8569[JRKSJR6]第七学区首先,有若干种\(O(n\logV)\)的暴力。我们选择其中操作比较简单的一种:对于每一位,先求出所有\(0\)段的长度之和,然后用所有区间的长度之和减掉......
  • [2022.10.14]Java方法
    加上static变成类变量Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用设计方......
  • Test 2022.10.12
    今天是紫黑专场T1\(GreedyChange\)分析说实话我并没有太搞懂这道黑题,要我解释的话也并不能太清楚地说出来,只是对着题解老老实实整理了一遍,迷迷糊糊地打出来,大概就是对......
  • JavaWeb学习日记2022.10.13
    排序查询(P13)/*排序查询SELECT字段列表FROM表名ORDERBY排序字段名1[排序方式1],排序字段名2[排序方式2]...;排序方式ASC:升序排列(默认值)DESC:降序排列*/--1......
  • 【图床】2022.10.08——雨夜西湖
    水汽浩荡,自屋后腾起。做个梦吧……时间:2021.12.09地点:湖滨同行:Hql设备:a7r3a+G24105F4调整后效果最为惊艳的一张图,r3的锐度和宽容度得以让我大幅度的调整光线、依......
  • 【闲话】2022.10.13
    今天……没有考试!Bk:就像回到了家一样。不用说,这就是家旁边。headto_cdqandAKNOIP:题我改不出来怎么办,我对着题解改的,就差把它们并到一起了'bikuhiku':你不要对着题解......
  • 2022.10.13 CSP2022 模拟赛三
    Source:JOI2018FinalT2-T5绝了会最后一题不会T2,麻了。美术展览显然的事情:在规定\(A\)的值域\([l,r]\)之后,对于所有\(A_i\in[l,r]\),都选进来一定最优。按\(A......
  • 2022.10.13小记
    24岁倒计时84天关于有点浪漫的事截止今日分数-8未来可期,不错不错真不错开心今日穿搭,背带牛仔裤+短上衣,有一点点小暴露,但是我都一直穿着外套。最重要的是冷的有点肚......