首页 > 其他分享 >ARC140D 做题笔记

ARC140D 做题笔记

时间:2023-09-25 21:22:21浏览次数:69  
标签:sz cnt int 笔记 times 基环树 ARC140D mod

洛谷题目链接

ATcoder 题目链接

好题。(不过绝大部分题解全在瞎说)

看到 $n$ 个点 $n$ 条边且每个点只有一条出边很容易的想到基环树。

而最后每个连通块一定是一个基环树,那么统计连通块的数量就相当于统计基环树的数量。

既然有基环树,这种题绝对不能枚举然后求连通块数量,一定是枚举连通块求它在多少种情况中会出现。

首先先扫一遍,把确定的边用并查集建好,同时维护每个树的点数量,变数量,这样就能够方便判断它是不是一个基环树了。

从基环树森林上断掉任意条边,一定会形成若干颗森林和若干颗基环树,这点十分显然,对于断开后仍是基环树的情况,可以直接统计答案了(因为日后无论怎么连始终是一个连通块),此时记输入的 $a$ 数组中有 $x$ 个 $-1$,方案为 $n^x$。(乘法原理)

接着考虑树,树中一定是有一个点向外连的边还没有确定,如果将这个边连到输入时就有的基环树上,此时的答案我们已经在输入时统计完了,所以唯一剩下的情况就是树连到树上形成基环树。

此时仍然不好考虑,不妨枚举一些东西,枚举这个基环树是由 $k$ 颗树构成的,然后发现倘若这 $k$ 颗树的根分别是 $a_1$ $a_2$ $a_3\cdots a_k$,那么由这些树互相连接组成基环树的方案数为 $sz_{a_1}\times sz_{a_2}\times sz_{a_3}\cdots \times sz_{a_k}$,当然这只是第 $i$ 颗基环树连向第 $i\bmod k+1$ 棵树的方案数。

事实上,我们还要对于这 $i$ 颗树进行排列后第 $i$ 颗连向第 $i+1$ 颗,这样才能不重不漏的计数。

排列的数量为 $k!$,但事实上并不是。

因为 $a_1$ $a_2$ $\cdots a_k$ 和 $a_2$ $a_3$ $\cdots a_k$ $a_1$ 是一样的,这种就是环状的情况,所以要除以 $k$。

如果有 $k$ 颗树 $a_1$ $a_2$ $a_3\cdots a_k$,那么连接成的基环树的数量就是 $(k-1)!\times sz_{a_1}\times sz_{a_2}\cdots \times sz_{a_k}$ 了。

于是枚举完 $k$,$(k-1)!$ 是可以提出来的,就剩下这样一个问题:从长度为 $n$ 的序列中选择 $k$ 项,求这些项的乘积和,设 $F_{i,j}$ 为前 $i$ 个数中选择 $j$ 个的乘积和,这是一个 $n^2$ 的劣质 DP。

此时发现枚举 $k$ 已经没有意义了,我们可以在计算完 $F$ 后,设 $cnt$ 为输入完后统计出树的数量,$F_{cnt,i}\times (i - 1)!$ 即为由 $i$ 颗树组成基环树的方案数了。

但答案仅仅如此吗?并不是,因为还有其余的 $-1$ 的 $a$ 没有选取,建基环树消耗了 $i$ 个 $-1$ 节点,剩下的 $-1$ 节点减一减就得到了,设剩下的 $-1$ 节点有 $sum$ 个,还是乘法原理 $n^sum$。

至此,这道题做完了:

#include <bits/stdc++.h>
#define int long long
#define For(i, a, b) for (int i = (a); i <= (b); i ++)
using namespace std;
int n, ans, cnt, cnt_1;
int a[2005], fac[2005], sum[2005];
int F[2005][2005];
const int mod = 998244353;
bool f, vis[2005];
int fa[2005], sz[2005], edge[2005];
int q_pow (int x, int y) {
    if (y == 0) return 1;
    if (y & 1) return x * q_pow (x * x % mod, y >> 1) % mod;
    return q_pow (x * x % mod, y >> 1) % mod;
}
int find (int x) {return (fa[x] == x ? x : fa[x] = find (fa[x]) );}
void merge (int x, int y) {
    int fx = find (x), fy = find (y);
    if (fx == fy) edge[fx] ++;
    else {
        fa[fy] = fx;
        sz[fx] += sz[fy];
        edge[fx] += edge[fy] + 1;
    }
}
signed main () {
    fac[0] = 1;
    For (i, 1, 2000) {
        fac[i] = fac[i - 1] * i % mod;
        fa[i] = i;
        sz[i] = 1;
    }
    cin >> n;
    For (i, 1, n) {
        cin >> a[i];
        if (a[i] == -1) {
            ++ cnt_1;
            continue;
        } else merge (i, a[i]);
    }
    For (i, 1, n) {
        if (fa[i] == i) {
            if (edge[i] == sz[i]) ans = (ans + q_pow (n, cnt_1) ) % mod;
            else sum[++ cnt] = sz[i];
        }
    }
    F[0][0] = 1;
    For (i, 1, cnt) For (j, 0, i) {
        F[i][j] = F[i - 1][j];
        if (j) F[i][j] = (F[i][j] + F[i - 1][j - 1] * sum[i]) % mod;
    }
    For (i, 1, cnt) {
        ans = (ans + F[cnt][i] * q_pow (n, cnt_1 - i) % mod * fac[i - 1]) % mod;
    }
    cout << ans;
    return 0;
}

 

标签:sz,cnt,int,笔记,times,基环树,ARC140D,mod
From: https://www.cnblogs.com/Xy-top/p/17728876.html

相关文章

  • 【学习笔记】(29) 笛卡尔树
    定义与性质笛卡尔树是一种二叉树,每一个结点由一个键值二元组\((k,w)\)构成。要求\(k\)满足二叉搜索树的性质,而\(w\)满足堆的性质。,也就是说,对于一个节点\(i\)的左儿子\(l_i\)和右儿子\(r_i\),一定满足\(l_i<i<r_i\)(下标\(k\)满足二叉搜索树的性质)且\(v_{l_i}\)与......
  • 组合数学学习笔记
    这是一位数学小萌新看oi-wiki的一点点收获。二项式定理二项式定理是组合数学中很基础且很重要的定理,它的式子为:\((a+b)^n=\sum_{i=0}^n\binom{n}{i}a^ib^{n-i}\)可以通过归纳法剖析\((a+b)^n\)的过程证明其正确性。范德蒙德卷积:\(\large\sum_{i=0}^k\binom{n}{i}......
  • 【笔记】机器学习基础 - Ch6.5-6 Kernel Methods
    6.5Sequencekernels考虑拓展\(K:\calX\timesX\to\mathbb{R}\)到\(\calX\)不是向量空间的情况,例如序列、图像等等。现在令\(\calX\)为字符串的集合,对应的核称为序列核sequencekernels;一种序列核的框架,称为rationalkernels,建立在称为加权转换器weightedtransduce......
  • Python学习笔记1
    a="好的,测试字符tester"b=17c=3print(a[1:5])#从第1(包含)个字符取到第5(不包含)个字符print(a[:3])#取到第3个字符(不含3)print(a[-5:-1])#取倒数第5个到倒数第1个print(a[-1:])#取最后一个字符print(len(a))#字符长度#exit()#退出与quit()一样,里面......
  • 信2105-3孟德昊阅读笔记规划
    这学期建民老师要求了我们每人进行不少于三本书的阅读,并给了我们很多的可读书籍的选择。我打算选择《软件需求》《软件需求模式》《敏捷软件需求》三本书来进行阅读,并作出相应的读书笔记,在读完之后进行认真的读书讨论,真正做到完全理解书中的内容,不是为了读书而读书,而是为了自己而......
  • 动态规划——区间DP 学习笔记
    动态规划——区间DP学习笔记不含四边形不等式优化。定义线性动态规划的局限性在于,它只能顺推或倒退,而不能有子区间依赖的问题。区间动态规划是线性动态规划的扩展,它将问题划分为若干个子区间,并通过定义状态和状态转移方程来求解每个子区间的最优解,最终得到整个区间的最优解。......
  • 读书笔记——《软件需求》其一
    《软件方法》是计算机科学领域的经典之作,由EdsgerW.Dijkstra于1975年出版。这本书对软件工程和程序设计方面的思想和方法进行了深入的研究和探讨,对于软件开发人员来说具有重要的启发和指导意义。在书中,Dijkstra强调了程序设计的正确性和可读性的重要性。他认为程序应该被认为是......
  • tarjan学习笔记
    tarjan学习笔记0.前置知识强连通图在一个有向图中,若从任意一点可以到达其他所有点,则称之为强连通图强连通分量(SCC)一个图中的极大强连通性质子图(强连通图的强连通分量是它本身)\(\small{极大强连通子图指一个不能加入另外的点的强连通子图(一个强连通子图可能包含一个或多......
  • 模式识别与机器学习——生成式分类器 课程笔记
    有监督学习:从有标记的数据中学习推断函数目标函数:\(Y=f(x)\)或\(P(Y|X)\)注意:条件概率用小写p表示,先验概率用大写P表示。贝叶斯判别原则给定观测值X,判断其属于\(\omega1\)类还是\(\omega2\)类,最小化误差概率条件下,\(P(\omega1|X)>P(\omega2|X)\)则判断成\(X\in\omega1\),......
  • 《梦断代码》阅读笔记01
    1、与其他的书籍很不同的一点是:这本书有第0章而第0章有这么一句话,也是将我这两年来学习技术的心理状态给描绘了个大概:“helloworld”程序一无所用,但足以蛊惑人心,多少软件雄心勃勃,但最终未结善果。不得不承认的一点是,我当初刚开始使用IDEA编程工具学习Java的时候,坚持学习下去......