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

我:“???”


# 题面

给出 \(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. 02.java基础(一)java的基础、方法和数组

    目录 Java基础 Java特性 Java程序运行机制 Java基础语法 1.数据类型 基本类型 引用类型 数据类型扩展 String类型内存分配过程 转义字符 类型转换 变量 常量 2.运算符 逻辑 ...

  2. VS Code第一部分--创建

    第一步:Win键+R  cmd 打开之后  输入 vue ui 运行结束后  会显示一个仪表盘页面 点击左下方的更多 点击项目管理器 点击创建  输入自己创建的文件夹地址  按回车保存 点击下方的创建 ...

  3. Tomcat集群配置--负载均衡

    Tomcat集群配置学习篇-----分布式应用 现目前基于javaWeb开发的应用系统已经比比皆是,尤其是电子商务网站,要想网站发展壮大,那么必然就得能够承受住庞大的网站访问量:大家知道如果服务器访问 ...

  4. 排查前端接受后端的map产生的字段错误

    报错内容 [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingExce ...

  5. 地址重写了,只是ip 没转发,应该是9999那个才对,rewrite /sbgl/(.*) http://127.0.0.1:9999/$1 permanent;,这样,

    记录想nginx搞路径重写的失败历程. 1.想将从nginx发出的127.0.0.1:80 请求过来的带sbgl的字眼去掉,然后,代理为127.0.0.1:9999, 所以我就百度出这个  这个  r ...

  6. uml类图中的+,-,#符号的含义

    描述类的属性的可见性: UML中,可见性分为4级 1.public 公用的 :用+ 前缀表示 ,该属性对所有类可见 2.protected 受保护的:用 # 前缀表示,对该类的子孙可见 3.priva ...

  7. Win10家庭版找不到组策略gpedit.msc怎么办

    Win10家庭版找不到组策略gpedit.msc怎么办 @echo off pushd "%~dp0" dir /b %systemroot%\Windows\servicing\ ...

  8. Adobe Acrobat PDF Reader DC软件下载

    安装包下载 https://get.adobe.com/en/reader/enterprise/ ftp下载,按日期排序 ftp://ftp.adobe.com/pub/adobe/reader/w ...

  9. P5731 蛇形方阵

    P5731 [深基5.习6]蛇形方阵 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) //为什么用动态二维数组 --->To play to user's input, but ...

  10. CocosCreator基于jenkins自动构建

    1.新建Item,输入名称后选择Freestyle project后点击确定 2.配置项目,自定义工作目录 3.配置源码管理和要摘取的分支 4.构建触发器选择github触发 5.构建选择执行wind ...