传送门

题目大意

  求出\(n\)个点的简单(无重边无自环)有标号无向连通图数目。\(n\leq 130000\)。

题解

  题意非常简单,但做起来很难。这是道生成函数经典题,博主当做例题学习用的。博主看到题解后感到非常惊讶:生成函数还能这么玩!

  步入正题。首先我们要定义生成函数\(F(x)=\sum\limits_{i\geq 0}f_i\dfrac{x^i}{i!}\),其中\(f_i\)表示\(i\)个点无向连通图数目。

  定义生成函数\(G(x)=\sum\limits_{i\geq 0}\dfrac{F^i(x)}{i!}\)。观察发现,\(G\)的第\(i\)项系数表示表示的是\(i\)个连通块构成的若干个结点的图的方案数,\(F(x)\)用\(\text{EFG}\)是因为会牵扯到组合数选择要除掉各个对应的阶乘,\(G(x)\)除掉\(i!\)的阶乘是因为\(i\)组中会重复。不难发现:\(G(x)\)表示的是若干结点的无向图总数!

  根据泰勒展开有:

\[G(x)=e^{F(x)}
\]

  所以我们有:

\[F(x)=\ln G(x)
\]

  多项式求\(\ln\)即可。

  复杂度:\(\text{O}(n\log n)\)。

  归纳上面的思路:利用任意个点连通图的数目与任意个点图的数目列等式,然后反解连通图的数目,从而得到答案

代码

#include <bits/stdc++.h>

using namespace std;

const int maxn = 130000 + 5;
const int P = 1004535809, g = 3; int inc(int a, int b) { return (a += b) >= P ? a-P : a; }
int qpow(int a, int b) {
int res = 1;
for (int i = a; b; i = 1ll*i*i%P, b >>= 1)
if (b & 1) res = 1ll*res*i%P;
return res;
} int W[maxn << 3], inv[maxn << 2], fac[maxn << 2], ifac[maxn << 2];
void prework(int n) {
for (int i = 1; i < n; i <<= 1) {
W[i] = 1;
for (int j = 1, Wn = qpow(g, (P-1)/i>>1); j < i; j++) W[i+j] = 1ll*W[i+j-1]*Wn%P;
}
inv[1] = fac[0] = ifac[0] = 1;
for (int i = 2; i < n; i++) inv[i] = 1ll*(P-P/i)*inv[P%i]%P;
for (int i = 1; i < n; i++) fac[i] = 1ll*fac[i-1]*i%P, ifac[i] = 1ll*ifac[i-1]*inv[i]%P;
} void ntt(int *a, int n, int opt) {
static int rev[maxn << 2];
for (int i = 1; i < n; i++)
if ((rev[i] = rev[i>>1]>>1|(i&1?n>>1:0)) > i) swap(a[i], a[rev[i]]);
for (int q = 1; q < n; q <<= 1)
for (int p = 0; p < n; p += q << 1)
for (int i = 0, t; i < q; i++)
t = 1ll*W[q+i]*a[p+q+i]%P, a[p+q+i] = inc(a[p+i], P-t), a[p+i] = inc(a[p+i], t);
if (~opt) return;
for (int i = 0; i < n; i++) a[i] = 1ll*a[i]*inv[n]%P;
reverse(a+1, a+n);
} struct poly {
vector<int> A;
int len;
poly(int a0 = 0) : len(1) { A.push_back(a0); }
int &operator [] (int i) { return A[i]; }
void write() {
for (int i = 0; i < len; i++) printf("%d ", A[i]);
putchar('\n');
}
void load(int *from, int n) {
A.resize(len = n);
memcpy(&A[0], from, sizeof(int) * len);
}
void cpyto(int *to, int n) {
memcpy(to, &A[0], sizeof(int) * min(len, n));
}
void resize(int n = 0) {
if (!n) { while (len > 1 && !A[len - 1]) len--; A.resize(len); } else A.resize(len = n, 0);
}
} F, G; poly poly_inv(poly A) {
poly B = poly(qpow(A[0], P-2));
for (int len = 1; len < A.len; len <<= 1) {
static int x[maxn << 2], y[maxn << 2];
for (int i = 0; i < len << 2; i++) x[i] = y[i] = 0;
A.cpyto(x, len << 1), B.cpyto(y, len);
ntt(x, len << 2, 1), ntt(y, len << 2, 1);
for (int i = 0; i < len << 2; i++) x[i] = inc(y[i], inc(y[i], P-1ll*x[i]*y[i]%P*y[i]%P));
ntt(x, len << 2, -1);
B.load(x, len << 1);
}
return B.resize(A.len), B;
} poly operator + (poly A, poly B) {
if (A.len < B.len) A.resize(B.len);
for (int i = 0; i < B.len; i++) A[i] = inc(A[i], B[i]);
return A.resize(), A;
} poly operator - (poly A, poly B) {
if (A.len < B.len) A.resize(B.len);
for (int i = 0; i < B.len; i++) A[i] = inc(A[i], P-B[i]);
return A.resize(), A;
} int getsize(int n) { int N = 1; while (N < n) N <<= 1; return N; } poly operator * (poly A, poly B) {
static int x[maxn << 2], y[maxn << 2];
int len = getsize(A.len + B.len - 1);
for (int i = 0; i < len; i++) x[i] = y[i] = 0;
A.cpyto(x, A.len), B.cpyto(y, B.len);
ntt(x, len, 1), ntt(y, len, 1);
for (int i = 0; i < len; i++) x[i] = 1ll*x[i]*y[i]%P;
ntt(x, len, -1);
return A.load(x, A.len + B.len - 1), A.resize(), A;
} poly poly_deri(poly A) {
for (int i = 0; i < A.len - 1; i++) A[i] = 1ll*A[i+1]*(i+1)%P;
return A[A.len - 1] = 0, A.resize(), A;
} poly poly_int(poly A) {
for (int i = A.len - 1; i; i--) A[i] = 1ll*A[i-1]*inv[i]%P;
return A[0] = 0, A;
} poly poly_ln(poly A) {
poly B = poly_deri(A) * poly_inv(A);
return B.resize(A.len), poly_int(B);
} int n; int main() {
scanf("%d", &n); prework((n+1)<<2);
G.resize(n+1);
for (int i = 1; i <= n; i++) G[i] = 1ll*qpow(2, 1ll*i*(i-1)/2%(P-1))*ifac[i]%P;
G[0] = 1;
F = poly_ln(G);
printf("%d", 1ll*F[n]*fac[n]%P);
return 0;
}

[洛谷P4841][集训队作业2013]城市规划的更多相关文章

  1. [题解] BZOJ 3456 洛谷 P4841 [集训队作业2013]城市规划 多项式,分治FFT

    题目 令\(f_i\)表示n个点的答案.考虑容斥,用所有连边方案减去有多个连通块的方案.枚举1号点所在的连通块大小: \(f_i=2^{i(i-1)/2}-\sum_{j>0}^{i-1}f_j ...

  2. [题解] LuoguP4841 [集训队作业2013]城市规划

    Description 求\(n\)个点无重边.无自环.带标号的无向联通图个数,对\(1004535809\)(\(479 \times 2^{21} + 1\))取模.\(n \le 130000\ ...

  3. bzoj 3236: 洛谷 P4396: [AHOI2013]作业 (莫队, 分块)

    题目传送门:洛谷P4396. 题意简述: 给定一个长度为\(n\)的数列.有\(m\)次询问,每次询问区间\([l,r]\)中数值在\([a,b]\)之间的数的个数,和数值在\([a,b]\)之间的不 ...

  4. Solution -「集训队作业 2013」「洛谷 P4841」城市规划

    \(\mathcal{Description}\)   link.   求 \(n\) 个结点的简单无向连通图个数,对 \(1004535809~(479\times2^{21}+1)\) 取模.   ...

  5. 洛谷 P4841 城市规划 解题报告

    P4841 城市规划 题意 n个有标号点的简单(无重边无自环)无向连通图数目. 输入输出格式 输入格式: 仅一行一个整数\(n(\le 130000)\) 输出格式: 仅一行一个整数, 为方案数 \( ...

  6. 洛谷P4841 城市规划(生成函数 多项式求逆)

    题意 链接 Sol Orz yyb 一开始想的是直接设\(f_i\)表示\(i\)个点的无向联通图个数,枚举最后一个联通块转移,发现有一种情况转移不到... 正解是先设\(g(n)\)表示\(n\)个 ...

  7. 洛谷P4841 城市规划 [生成函数,NTT]

    传送门 题意简述:求\(n​\)个点的简单无向连通图的数量\(\mod \;1004535809​\),\(n \leq 130000​\) 经典好题呀!这里介绍两种做法:多项式求逆.多项式求对数 先 ...

  8. 洛谷 P4841 城市规划

    构造简单无向图的EGF: \[ G(x)=\sum_{i}^{\infty}2^{\binom{i}{2}}\cdot\frac{x^i}{i!} \] 构造简单无向连通图的EGF: \[ F(x)= ...

  9. [洛谷P4841]城市规划

    题目大意:求$n$个点的带标号的无向连通图的个数 题解:令$F(x)$为带标号无向连通图个数生成函数,$G(x)$为带标号无向图个数生成函数 那么$G(x) = \sum_{i=0}^{\infty} ...

随机推荐

  1. iView 实战系列教程(21课时)_4.iView 实战教程之布局篇(二)

    https://github.com/iview/iview 下载iview的代码 Layout布局大概的样子 Iview的源代码.Layout 组件比较简单,,里面一个slot Sider是最复杂的 ...

  2. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_03 过滤器_2_FileNameFilter过滤器的使用和Lambda表达式

    复制一份上一节的代码 匿名内部类的形式 FilenameFilter 只有一个Accept方法.这样我们就可以使用lambda表达式 lambda表达式的前提条件 参数类型和,返回的大括号 都可以省掉 ...

  3. Nginx-Lua模块的执行顺序(转)

    一.nginx执行步骤 nginx在处理每一个用户请求时,都是按照若干个不同的阶段依次处理的,与配置文件上的顺序没有关系,详细内容可以阅读<深入理解nginx:模块开发与架构解析>这本书, ...

  4. C#扩展方法 DataTable.ToEntitys

    类A需要添加功能,我们想到的就是在类A中添加公共方法,这个显而易见肯定可以,但是由于某种原因,你不能修改类A本身的代码,但是确实又需要增加功能到类A中去,怎么办? 这个时候扩展方法(Extension ...

  5. 【AndroidFramework】【EMMC拷机】混合拷机时盒子待机

    [AndroidFramework][EMMC拷机]混合拷机时盒子待机 问题结论 暂时确定为误按键,不是故障.问题关闭.后续完全保证无按键(物理隔离)情况下如果出现待机,请反馈. 问题描述 [EMMC ...

  6. Hadoop and Big Data

    Hadoop(1): HDFS Basics Hadoop(2):HDFS Block Management Hadoop(3): Prepare inputs for MapReduce mappe ...

  7. 应用安全 - 软件漏洞 - 泛微OA漏洞汇总

    SQL注入 前台SQL注入 用户名:admin' or password like 'c4ca4238a0b923820dcc509a6f75849b' and 'a'='a 密码: 1 验证页面参数 ...

  8. JavaScript FSO属性大全

    什么是FSO? FSO 即 File System Object 文件系统对象,是一种列表 Windows 磁盘目录和文件,对目录和文件进行删除.新建.复制.剪切.移动等操作的技术.使用 FSO 网站 ...

  9. 剑指Offer编程题(Java实现)——数组中的重复数字

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

  10. Codeforces 475D 题解(二分查找+ST表)

    题面: 传送门:http://codeforces.com/problemset/problem/475/D Given a sequence of integers a1, -, an and q ...