讲题人:“这是一个很经典的模型,大家应该都会”

我:“???”


# 题面

给出 \(m\),求所有 \(m\) 个点的有标号强联通竞赛图的哈密顿回路数量的平均数。答案对 \(998244353\) 取模。

输入 \(n\),对每个 \(m=1\sim n\) 求解。

数据规模:\(n\le10^5\)。


# 解析

问题分成两个部分:

  • 所有 \(m\) 个点的竞赛图的哈密顿回路数量;注意到只有强联通的竞赛图有哈密顿回路,所以计算时不用管强联通;
  • \(m\) 个点的强联通竞赛图数量。

第一个部分。我们发现对一个竞赛图计算它的哈密顿回路没法做,考虑对一个哈密顿回路计算它出现在多少个竞赛图中

哈密顿回路从 \(1\) 处断开,就是一个从 \(1\) 开头的 \(1\sim m\) 的排列,数量为 \((m-1)!\)。我们钦定这样一条哈密顿回路在竞赛图上,相当于已经给 \(m\) 条边钦定了方向,剩下的 \(\frac{m(m-1)}2-m\) 条边随便定向,即哈密顿回路总数为:

\[2^{\frac{m(m-1)}{2}-m}\times(m-1)!
\]

特判一下 \(n\le2\)。

第二个部分。记 \(f_i\) 表示 \(i\) 个点的强联通竞赛图的数量,我们要计算 \(f_1\sim f_n\)。计算这些值,可以考虑生成函数 —— 注意到有标号,记 \(f_i\) 的 EGF 为 \(F(x)\)。

直接限制强联通并不好算,于是正难则反。计算一定没有强联通的竞赛图的数量。

重要性质

将竞赛图强联通缩点后的图记为 \(T\),对 \(T\) 做拓扑排序,则按拓扑序排列的点在 \(T\) 上形成一条链。

如果竞赛图不是强联通,则一定存在多个强联通分量,结合上述性质,可以找到拓扑序最小的一个强联通分量 \(G_1\),而剩下的图 \(G_2\) 是一个任意的竞赛图。由于 \(G_1\) 是极大的强联通分量,且拓扑序最小,则 \(G_1\) 和 \(G_2\) 之间的所有边都是从 \(G_1\) 连向 \(G_2\)。

我们可以枚举 \(G_1\) 的大小为 \(i\),则 \(G_1\) 是大小为 \(i\) 的强联通竞赛图,而 \(G_2\) 为大小为 \(m-i\) 的任意竞赛图。记 \(g_i\) 为 \(i\) 个点的任意竞赛图数量。可以写出转移式:

\[f_s=g_s-\sum_{i=1}^{s-1}\binom{s}{i}f_ig_{s-i}
\]

有组合数,能够拆成 EGF 的形式。记 \(G(x)\) 为 \(g_i\) 的 EGF:

\[\begin{aligned}
\frac{f_s}{s!}=\frac{g_s}{s!}-\sum_{i=1}^{s-1}\frac{f_i}{i!}\times\frac{g_{s-i}}{(s-i)!}\\
F(x)=G(x)-F(x)G(x)
\end{aligned}
\]

分治 NTT 或者多项式求逆,但是感觉多项式求逆好写些……


# 源代码

/*Lucky_Glass*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MOD = 998244353, N = 1e5 + 10, L = 262144;
#define con(typ) const typ & inline int add(int a, con(int) b) {
return (a += b) >= MOD ? a - MOD : a;
}
inline int sub(int a, con(int) b) {
return (a -= b) < 0 ? a + MOD : a;
}
inline int mul(con(int) a, con(int) b) {
return int(1ll * a * b % MOD);
}
inline int iPow(int a, int b) {
int r = 1;
while ( b ) {
if ( b & 1 ) r = mul(a, r);
a = mul(a, a), b >>= 1;
}
return r;
} namespace BASICPOLY {
int rev[L + 10], elg2[L + 10], powg[L + 10];
void init() {
elg2[1] = 0, powg[0] = 1, powg[1] = iPow(3, (MOD - 1) >> 18);
for (int i = 2; i <= L; i++) {
elg2[i] = elg2[(i + 1) >> 1] + 1;
powg[i] = mul(powg[i - 1], powg[1]);
}
}
void ntt(int *arr, con(int) len, con(int) typ) {
for (int i = 1; i < len; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
if ( i < rev[i] ) swap(arr[i], arr[rev[i]]);
}
for (int i = 1, ii = 2; i < len; i <<= 1, ii <<= 1) {
int s = L >> elg2[ii];
for (int j = 0; j < len; j += ii) {
int *a = arr + j, *b = a + i, *p = powg, q = *b;
for (int k = 0; k < i; k++, a++, q = mul(*(p += s), *(++b)))
*b = sub(*a, q), *a = add(*a, q);
}
}
if ( typ == -1 ) {
reverse(arr + 1, arr + len);
int ivn = MOD - ((MOD - 1) >> elg2[len]);
if ( mul(ivn, len) != 1 ) printf("???");
for (int i = 0; i < len; i++) arr[i] = mul(arr[i], ivn);
}
}
int ta[L + 10], tb[L + 10];
void polyMul(int *a, int *b, con(int) la, con(int) lb, int *r,
con(int) fr = -1) {
int lr = la + lb - 1, len = 1 << elg2[lr];
for (int i = 0; i < la; i++) ta[i] = a[i];
for (int i = la; i < len; i++) ta[i] = 0;
for (int i = 0; i < lb; i++) tb[i] = b[i];
for (int i = lb; i < len; i++) tb[i] = 0;
ntt(ta, len, 1), ntt(tb, len, 1);
for (int i = 0; i < len; i++) ta[i] = mul(ta[i], tb[i]);
ntt(ta, len, -1);
for (int i = 0, ii = ~fr ? fr : lr; i < ii; i++) r[i] = ta[i];
}
void polyInv(int *a, int *r, con(int) len) {
if ( len == 1 ) {
r[0] = iPow(a[0], MOD - 2);
return;
}
polyInv(a, r, (len + 1) >> 1);
int llen = 1 << elg2[len << 1];
for (int i = 0; i < len; i++) ta[i] = a[i];
for (int i = len; i < llen; i++) ta[i] = 0;
for (int i = 0, ii = (len + 1) >> 1; i < ii; i++) tb[i] = r[i];
for (int i = (len + 1) >> 1; i < llen; i++) tb[i] = 0;
ntt(ta, llen, 1), ntt(tb, llen, 1);
for (int i = 0; i < llen; i++)
ta[i] = mul(tb[i], sub(2, mul(ta[i], tb[i])));
ntt(ta, llen, -1);
for (int i = 0; i < len; i++) r[i] = ta[i];
}
} int fac[N], ifac[N], ara[N], arb[N]; int calc(con(int) n) {
if ( n <= 2 ) return n == 1;
return mul(fac[n - 1], iPow(2, (n * (n - 1ll) / 2 - n) % (MOD - 1)));
}
int funS(con(int) n) {
return iPow(2, n * (n - 1ll) / 2 % (MOD - 1));
}
void init() {
fac[0] = 1;
for (int i = 1; i < N; i++)
fac[i] = mul(fac[i - 1], i);
ifac[N - 1] = iPow(fac[N - 1], MOD - 2);
for (int i = N - 2; ~i; i--)
ifac[i] = mul(ifac[i + 1], i + 1);
BASICPOLY::init();
for (int i = 1; i < N; i++) ara[i] = mul(funS(i), ifac[i]);
ara[0]++;
BASICPOLY::polyInv(ara, arb, N);
ara[0]--;
BASICPOLY::polyMul(ara, arb, N, N, ara, N);
for (int i = 1; i < N; i++) ara[i] = mul(ara[i], fac[i]);
}
int main() {
init();
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
if ( ara[i] )
printf("%d\n", mul(calc(i), iPow(ara[i], MOD - 2)));
else printf("-1\n");
}
return 0;
}

THE END

Thanks for reading!

你喜欢海风咸咸的气息

踩着湿湿的沙砾

你说人们的骨灰应该撒进海里

你问我死后会去哪里

有没有人爱你

世界能否不再

——《海底(Cover)》 By 祖娅纳惜

「SOL」射命丸文的笔记 (洛谷)的更多相关文章

  1. loj2734「JOISC 2016 Day 2」女装大佬 || 洛谷P3615 如厕计划

    loj2734 洛谷P3615 http://218.5.5.242:9021/problem/185 不会做... 题解(来自ditoly): 这一步更详细的解释(来自kkksc03): 还是从后面 ...

  2. 斜率优化dp学习笔记 洛谷P3915[HNOI2008]玩具装箱toy

    本文为原创??? 作者写这篇文章的时候刚刚初一毕业…… 如有错误请各位大佬指正 从例题入手 洛谷P3915[HNOI2008]玩具装箱toy Step0:读题 Q:暴力? 如果您学习过dp 不难推出d ...

  3. 边带权并查集 学习笔记 & 洛谷P1196 [NOI2002] 银河英雄传说 题解

    花了2h总算把边带权并查集整明白了qaq 1.边带权并查集的用途 众所周知,并查集擅长维护与可传递关系有关的信息.然而我们有时会发现并查集所维护的信息不够用,这时"边带权并查集"就 ...

  4. 解题笔记-洛谷-P1010 幂次方

    0 题面 题目描述 任何一个正整数都可以用2的幂次方表示.例如 137=2^7+2^3+2^0 同时约定方次用括号来表示,即a^b 可表示为a(b). 由此可知,137可表示为: 2(7)+2(3)+ ...

  5. 快速沃尔什变换(FWT)学习笔记 + 洛谷P4717 [模板]

    FWT求解的是一类问题:\( a[i] = \sum\limits_{j\bigoplus k=i}^{} b[j]*c[k] \) 其中,\( \bigoplus \) 可以是 or,and,xor ...

  6. [折腾笔记] 洛谷P1149-火柴棒等式 AC记

    原题链接: https://www.luogu.org/problem/P1149 题面简述: 给你n根火柴棍,你可以拼出多少个形如"A+B=C""A+B=C" ...

  7. STL Queue(队列)学习笔记 + 洛谷 P1540 机器翻译

    队(Queue) 队简单来说就是一个先进先出的“栈”,但是不同于标准“栈”的先进后出. 基本操作: push(x) 将x压入队列的末端 pop() 弹出队列的第一个元素(队顶元素),注意此函数并不返回 ...

  8. STL Stack(栈)学习笔记 + 洛谷 P1449 后缀表达式

    稍微看了看刘汝佳的白皮书,“实用主义”的STL实在是香到我了,而且在实验室大佬的推荐下我开始了stl的学习. 每篇附带一个题目方便理解,那行,直接开始. 毕竟是实用主义,所以就按照给的题目的例子来理解 ...

  9. 「LGR-049」洛谷7月月赛 D.Beautiful Pair

    「LGR-049」洛谷7月月赛 D.Beautiful Pair 题目大意 : 给出长度为 \(n\) 的序列,求满足 \(i \leq j\) 且 $a_i \times a_j \leq \max ...

  10. 「P4994」「洛谷11月月赛」 终于结束的起点(枚举

    题目背景 终于结束的起点终于写下句点终于我们告别终于我们又回到原点…… 一个个 OIer 的竞赛生涯总是从一场 NOIp 开始,大多也在一场 NOIp 中结束,好似一次次轮回在不断上演.如果这次 NO ...

随机推荐

  1. AFNI 步骤4-命令和预处理

    第一部分 AFNI命令和uber_subject.py的使用 略 第二部分 时间矫正 在扫描过程中,从第一个切片到最后一个切片之间存在一定的时间差,导致采集到的数据并不是一个时间点的. 在扫描过程中, ...

  2. beanshell 响应数据的解析与变量的保存

    获取响应的数据 response = prev.getResponseDataAsString() //prev.getResponseDataAsString是Jmeter提供的方法,可以调取上次请 ...

  3. RealSenseD435的一些参数整理

    一.深度相机D435 二.自校准功能 https://www.intelrealsense.com/self-calibration-for-depth-cameras/ https://dev.in ...

  4. 解决不了ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing啊

    我今天真的好难受,在我结束hbase的配置的后,又是成功运行了shell命令,我以为万事大吉,结果下午再用shell命令时,给我报了这个错,我按着网上说的删了点东西,还是解决不了,难受啊. 我现在时决 ...

  5. c/c++工程中为什么仅仅main.cpp引用其他源文件的头文件不够,源文件还要引用自身的头文件?

    原博客链接: https://blog.csdn.net/khwkhwkhw/article/details/49798985?utm_source=app&from=timeline 引言: ...

  6. Qt多线程编程之QThreadPool 和 QRunnable使用

    说到线程通常会想到QThread,但其实Qt中创建线程的方式有多种,这里主要介绍其中一种QRunnable,QRunnable和QThread用法有些不同,并且使用场景也有区别.要介绍QRunnabl ...

  7. macOS NSView改变frame后会出现黑色残留,应付的办法是不在drawRect上修改重新initWithFrame一下就行

    黑色部分就是残留.是因为绘制后保留了轨迹. 解决办法是不在drawRect中做处理重新写NSView,新增方法 initWithFrame - (void)drawRect:(NSRect)dirty ...

  8. superset2.0.0 支持MaxCompute 时间颗粒

    编译的时候需要在superset/superset/db_engine_specs以下路径增加一个 odps.py的文件 # Licensed to the Apache Software Found ...

  9. R语言广义线性模型(GLM)、全子集回归模型选择、检验分析全国风向气候数据|附代码数据

    全文链接:http://tecdat.cn/?p=30914 最近我们被客户要求撰写关于广义线性模型(GLM)的研究报告,包括一些图形和统计输出. 我们正和一位朋友讨论如何在R软件中用GLM模型处理全 ...

  10. vue 图片下载

       getBase64Image(img) {        var canvas = document.createElement("canvas");        canv ...