洛谷题面传送门

看到图计数的题就条件反射地认为是不可做题并点开了题解……实际上这题以我现在的水平还是有可能能独立解决的(

首先连通这个条件有点棘手,我们尝试把它去掉。考虑这题的套路,我们设 \(f_n\) 表示 \(n\) 个点的有标号 DAG 个数,\(g_n\) 表示 \(n\) 个点的有标号且弱联通的 DAG 个数,那么根据 \(\exp\) 式子的计算方式我们可以列出 \(f,g\) 生成函数之间的 exp 关系,又因为这题带标号,所以有:

Trick 1. 对于有标号图连通图计数问题,我们可以先计算出不限制连通的方案数,这样再对求得的序列的 EGF 做一遍 \(\ln\) 就可以得到待求序列的 EGF。

应用到此题上,就是设 \(F(x)\) 表示 \(f\) 序列的 EGF,\(G(x)\) 表示 \(g\) 序列的 EGF,那么 \(F(x)=\exp(G(x))\),因此我们求出 \(F(x)\) 后一遍 \(\ln\) 即可还原出 \(G(x)\)。

考虑怎么求 \(F(x)\)。对于 DAG 有一个性质,就是剥掉它入度为 \(0\) 的点后仍是一个 DAG,因此我们考虑枚举入度为 \(0\) 的点集 \(S\),但是这个点集很难恰好就是入度为 \(0\) 的点。所以我们可以考虑:

Trick 2. 对于 DAG 计数,我们可以考虑枚举其中入度为 \(0\) 的点集 \(S\) 并计算出剩余部分的方案数,但是这样会算重,因此需容斥,对于一个 \(S\) 而言其容斥系数就是 \((-1)^{|S|-1}\)。

因此我们枚举 \(S\) 的大小,有

\[f_i=\sum\limits_{j=1}^i\dbinom{i}{j}(-1)^{j-1}2^{j(i-j)}f_{i-j}
\]

其中 \(2^{j(n-j)}\) 表示在钦定的入度为 \(0\) 的点与剩余点之间连边的方案数。

诶呀,这里 \(2^{j(i-j)}\) 既涉及 \(i\) 又涉及 \(j\),怎么办呢?

Trick 3. \(2^{i-j}=2^{\binom{i}{2}}·\dfrac{1}{2^{\binom{j}{2}}}·\dfrac{1}{2^{\binom{i-j}{2}}}\),这样我们可以将原本与 \(i,j\) 都有关的东西拆成只与 \(i,j,i-j\) 有关的项,方便卷积

因此

\[f_i=\sum\limits_{j=1}^i\dfrac{i!}{j!(i-j)!}(-1)^{j-1}f_{i-j}2^{\binom{i}{2}}·\dfrac{1}{2^{\binom{j}{2}}}·\dfrac{1}{2^{\binom{i-j}{2}}}
\]

整理一下

\[\dfrac{f_i}{i!·2^{\binom{i}{2}}}=\sum\limits_{j=1}^i\dfrac{(-1)^{j-1}}{j!·2^{\binom{j}{2}}}·\dfrac{f_{i-j}}{(i-j)!·2^{\binom{i-j}{2}}}
\]

到这里,式子已经可以写成分治 FFT 的形式了,可以分治 FFT 求解,时间复杂度 2log。不过注意到咱们的分治 FFT 与求逆是紧密相连的,许多分治 FFT 的题都可以写成求逆的形式,此题也不例外。设

\[P(x)=\sum\limits_{i}\dfrac{f_i}{i!·2^{\binom{i}{2}}}x^i
\]
\[Q(x)=\sum\limits_{i}\dfrac{(-1)^{i-1}}{i!·2^{\binom{i}{2}}}(i>0)
\]

那么有 \(P(x)=P(x)Q(x)+1\),移个项可得 \(P(x)=\dfrac{1}{1-Q(x)}\)。\(1-Q(x)\) 常数项显然不为 \(0\),因此一遍求逆即可搞定 \(P(x)\),也可进而求出 \(F,G\)。

时间复杂度 \(n\log n\)。

  1. const int pr=3;
  2. const int ipr=332748118;
  3. const int MAXP=1<<18;
  4. const int INV2=MOD+1>>1;
  5. const int PHI=MOD-1;
  6. int fac[MAXP+5],ifac[MAXP+5],inv[MAXP+5];
  7. void init_fac(int n){
  8. for(int i=(fac[0]=ifac[0]=inv[0]=inv[1]=1)+1;i<=n;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
  9. for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*inv[i]%MOD;
  10. }
  11. int qpow(int x,int e){
  12. int ret=1;
  13. for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
  14. return ret;
  15. }
  16. int rev[MAXP+5];
  17. void NTT(vector<int> &a,int len,int type){
  18. int lg=31-__builtin_clz(len);
  19. for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
  20. for(int i=0;i<len;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
  21. for(int i=2;i<=len;i<<=1){
  22. int W=qpow((type<0)?ipr:pr,(MOD-1)/i);
  23. for(int j=0;j<len;j+=i){
  24. for(int k=0,w=1;k<(i>>1);k++,w=1ll*w*W%MOD){
  25. int X=a[j+k],Y=1ll*w*a[(i>>1)+j+k]%MOD;
  26. a[j+k]=(X+Y)%MOD;a[(i>>1)+j+k]=(X-Y+MOD)%MOD;
  27. }
  28. }
  29. } if(!~type){
  30. int ivn=qpow(len,MOD-2);
  31. for(int i=0;i<len;i++) a[i]=1ll*a[i]*ivn%MOD;
  32. }
  33. }
  34. vector<int> conv(vector<int> a,vector<int> b){
  35. int LEN=1;while(LEN<a.size()+b.size()) LEN<<=1;
  36. a.resize(LEN,0);b.resize(LEN,0);NTT(a,LEN,1);NTT(b,LEN,1);
  37. for(int i=0;i<LEN;i++) a[i]=1ll*a[i]*b[i]%MOD;
  38. NTT(a,LEN,-1);return a;
  39. }
  40. vector<int> getinv(vector<int> a,int len){
  41. vector<int> b(len,0);b[0]=qpow(a[0],MOD-2);
  42. for(int i=2;i<=len;i<<=1){
  43. vector<int> c(b.begin(),b.begin()+(i>>1));
  44. vector<int> d(a.begin(),a.begin()+i);
  45. c=conv(conv(c,c),d);
  46. for(int j=0;j<i;j++) b[j]=(2ll*b[j]-c[j]+MOD)%MOD;
  47. } return b;
  48. }
  49. vector<int> direv(vector<int> a,int len){
  50. vector<int> b(len,0);
  51. for(int i=1;i<len;i++) b[i-1]=1ll*i*a[i]%MOD;
  52. return b;
  53. }
  54. vector<int> inter(vector<int> a,int len){
  55. vector<int> b(len,0);
  56. for(int i=1;i<len;i++) b[i]=1ll*inv[i]*a[i-1]%MOD;
  57. return b;
  58. }
  59. vector<int> getln(vector<int> a,int len){
  60. vector<int> _a=direv(a,len),b=getinv(a,len);
  61. b=conv(b,_a);b=inter(b,len);return b;
  62. }
  63. int main(){
  64. init_fac(MAXP);vector<int> f(MAXP/2),g(MAXP/2);
  65. for(int i=1;i<MAXP/2;i++){
  66. int val=1ll*ifac[i]*qpow(INV2,1ll*i*(i-1)/2%PHI)%MOD;
  67. if(i&1) g[i]=MOD-val;else g[i]=val;
  68. } (g[0]+=1)%=MOD;f=getinv(g,MAXP/2);
  69. // for(int i=0;i<MAXP/2;i++) printf("%d\n",g[i]);
  70. for(int i=0;i<MAXP/2;i++) f[i]=1ll*f[i]*qpow(2,1ll*i*(i-1)/2%PHI)%MOD;
  71. f=getln(f,MAXP/2);int n;scanf("%d",&n);
  72. for(int i=1;i<=n;i++) printf("%d\n",1ll*f[i]*fac[i]%MOD);
  73. return 0;
  74. }

洛谷 P6295 - 有标号 DAG 计数(生成函数+容斥+NTT)的更多相关文章

  1. 洛谷P5206 [WC2019] 数树(生成函数+容斥+矩阵树)

    题面 传送门 前置芝士 矩阵树,基本容斥原理,生成函数,多项式\(\exp\) 题解 我也想哭了--orz rqy,orz shadowice 我们设\(T1,T2\)为两棵树,并定义一个权值函数\( ...

  2. P6295 有标号 DAG 计数

    P6295 有标号 DAG 计数 题意 求 \(n\) 个点有标号弱联通 DAG 数量. 推导 设 \(f_i\) 表示 \(i\) 个点有标号 DAG 数量(不保证弱联通),有: \[f(i)=\s ...

  3. 有标号DAG计数(生成函数)

    有标号DAG计数(生成函数) luogu 题解时间 首先考虑暴力,很容易得出 $ f[ i ] = \sum\limits_{ j = 1 }^{ i } ( -1 )^{ j - 1 } \bino ...

  4. 【洛谷5644】[PKUWC2018] 猎人杀(容斥+生成函数+分治NTT)

    点此看题面 大致题意: 有\(n\)个人相互开枪,每个人有一个仇恨度\(a_i\),每个人死后会开枪再打死另一个还活着的人,且第一枪由你打响.设当前剩余人仇恨度总和为\(k\),则每个人被打中的概率为 ...

  5. POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量

    POJ 1741. Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 34141   Accepted: 11420 ...

  6. 洛谷P4707 重返现世 [DP,min-max容斥]

    传送门 前置知识 做这题前,您需要认识这个式子: \[ kthmax(S)=\sum_{\varnothing\neq T\subseteq S}{|T|-1\choose k-1} (-1)^{|T ...

  7. 洛谷P4707 重返现世(扩展MinMax容斥+dp)

    传送门 我永远讨厌\(dp.jpg\) 前置姿势 扩展\(Min-Max\)容斥 题解 看纳尔博客去→_→ 咱现在还没搞懂为啥初值要设为\(-1\)-- //minamoto #include< ...

  8. 洛谷 P4336 黑暗前的幻想乡 —— 容斥+矩阵树定理

    题目:https://www.luogu.org/problemnew/show/P4336 当作考试题了,然而没想出来,呵呵. 其实不是二分图完美匹配方案数,而是矩阵树定理+容斥... 就是先放上所 ...

  9. 洛谷 P4707 - 重返现世(扩展 Min-Max 容斥+背包)

    题面传送门 首先看到这种求形如 \(E(\max(T))\) 的期望题,可以套路地想到 Min-Max 容斥 \(\max(S)=\sum\limits_{T\subseteq S}(-1)^{|T| ...

随机推荐

  1. gin 源码阅读(5) - 灵活的返回值处理

    gin 源码阅读系列文章列表: gin 源码阅读(1) - gin 与 net/http 的关系 gin 源码阅读(2) - http请求是如何流入gin的? gin 源码阅读(3) - gin 路由 ...

  2. python join的用法

    joinn其实就相当于用某个字符串来拼接列表或者元组中的元素 当然也可以将字符串以某一个str拼接起来 得出的结果自然也是字符串 ex1: results: 实例用处: 当我们从某个文件中读出内容时, ...

  3. DL4J实战之六:图形化展示训练过程

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<DL4J实战>系列的第六 ...

  4. [对对子队]会议记录4.13(Scrum Meeting 4)

    今天已完成的工作 梁河览 ​ 工作内容:初步完成存档功能 ​ 相关issue:实现游戏内UI界面使用的组件 马嘉 ​ 工作内容:找到了原料组件 ​ 相关issue:实现游戏内UI界面使用的组件 吴昭邦 ...

  5. Vue接收后端传过来excel表格的文件流并下载

    题外话:当接收文件流时要确定文件流的类型,但也有例外就是application/octet-stream类型,主要是只用来下载的类型,这个类型简单理解意思就是通用类型类似 var .object.ar ...

  6. virtual box搭建虚拟机nat和host only网络配置实用

    virtual box搭建虚拟机nat和host only网络配置实用 一.背景 二.需求 二.设置虚拟机的网络 1.创建一个全局的nat网络 2.添加主机网络管理器 3.设置虚拟机网络 1.网卡1设 ...

  7. 大牛针对零基础入门c语言详解指针(超详细)

    C语言指针说难不难但是说容易又是最容易出错的地方,因此不管是你要做什么只要用到C指针你就跳不过,今天咱们就以 十九个例子来给大家简单的分析一下指针的应用,最后会有C语言视频资料提供给大家更加深入的参考 ...

  8. Linux线程互斥学习笔记--详细分析

    一.互斥锁 为啥要有互斥? 多个进程/线程执行的先后顺序不确定,何时切出CPU也不确定. 多个进程/线程访问变量的动作往往不是原子的. 1. 操作步骤 (1)创建锁 // 创建互斥锁mutex pth ...

  9. 电路维修(双端队列 & 最短路)

    达达是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女翰翰,从而被收留在地球上. 翰翰的家里有一辆飞行车. 有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板的整体结构是一个$ ...

  10. 021中国大学生程序设计竞赛(CCPC)- 压力测试赛题解

    A.Matrix 挺狗的一道题,从开始冲到最后都没冲出来,都没啥思路. 其实分开考虑每个数的贡献,这个想法也存在过,就是不知道该怎么计算,我们考虑我们单独考虑一个数字\(i(1\leq i\leq n ...