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

我:“???”


# 题面

给出 \(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. java的特性和版本

    java的特性 简单性 面向对象性 可移植性(跨平台性) 高性能 安全性 健壮性 多线程 分布式 动态性 java的三个版本 javaSE(标准版),主要是桌面程序开发 javaME(微型版),主要是 ...

  2. 微信支付模式二java

    这个星期写了下微信支付模式二,在这里进行下整理 微信支付官方文档 1. 需要的配置..具体看下面的链接. https://pay.weixin.qq.com/wiki/doc/api/native.p ...

  3. Mysql 无法使用注释 带注释执行报错 Dbeaver

    一.场景 执行时,前面带一段注释,在dbeaver执行报语法错误 二.解决办法 在注释后面插入一个空格,识别注释后变成灰色,执行成功

  4. VUE3+VITE 常见问题解决

    reactive解构最深的一层,失去响应性问题 pinia创建的store,使用结构失去响应性 reactive包裹后的对象 重新赋值失去响应性 无法动态引入图片 在computed中传参数 vue3 ...

  5. pycharm 连接 docker容器

    1.ubuntu 18.04 先安装sudo apt-get install openssh-server 2.修改" /etc/ssh/sshd_config" 改成 Permi ...

  6. 读后笔记 -- Python 全栈测试开发 Chapter10:接口的设计与开发

    10.1 Django 框架 1. 几个主流的框架: 1)适合初学者的接口框架:Django,Flask 2)针对底层定义:Twisted 3)实现高并发:Tornado 2. install // ...

  7. Antlr语法优化过程记录

    背景 Modelica Spec中的语法文件在Antlr下表现很糟糕,至少是1个数量级的糟糕的性能表现 理论 语义谓词减慢速度 ATN图中多分支转换为单分支 可选放在词法开头和语法的结尾 避免前导可选 ...

  8. check power supply check cpu top

    lshw -c power power supply mwh https://www.eia.gov/energyexplained/electricity/electricity-in-the-us ...

  9. 解决每次centos7执行java --version git --version等命令时都要重新source /etc/profile后才能执行,否则找不到命令-转载

      linux mint 我们通常将环境变量设置在/etc/profile这个文件中,这个文件是全局的. /etc/profile:在登录时,操作系 统定制用户环境时使用的第一个文件 ,此文件为系统的 ...

  10. 接口拿到的id和传到后台的id不一致,导致查询详情和编辑报错

    碰到这个问题真是百思不得其解.接口上打印的值和数据库一致,浏览器查看response的反馈也一致.但是一在页面打印请求回来的值,就变了,变成了另一个id,但是其他数据又和数据库一致. 查了一圈也没有查 ...