题解

在我写过分治NTT,多项式求逆之后

我又一次写了多项式求ln

我们定义一个数列的指数型生成函数为

\(\sum_{i = 0}^{n} \frac{A_{i}}{i!} x^{i}\)

然后这个有个很好的性质,是什么呢,就是我们考虑两个排列\(A\)和\(B\),不改变原来的顺序,把它们合并成一个排列,方案数显然是

\(\binom{|A| + |B|}{|A|}\)

现在每个相同长度的排列\(A\)带有一个价值\(A_i\),\(B\)同理

\(C_{k} = \sum_{i = 0}^{k} \binom{k}{i}A_{i}B_{k - i}\)

\(\frac{C_{k}}{k!} = \sum_{i = 0}^{k} \frac{A_{i}}{i!} \cdot \frac{B_{k - i}}{(k - i)!}\)

这样的话两个指数型函数的卷积就是我们想要的排列总和除以\(n!\)我们可以卷积之后还原回去

然后我们考虑

\(G(x) = \sum_{i = 0}^{+\infty} \frac{2^{\binom{i}{2}}}{i!}\)表示\(i\)个点带标号的无向图个数

和\(C(x) = \sum_{i = 0}^{+\infty} \frac{c_i}{i!} x^{i}\)表示\(i\)个点带标号的无向联通图个数

然后我们可以列出来

\(G(x) = \frac{C(x)}{1!} + \frac{C^2(x)}{2!} + \frac{C^3(x)}{3!} + .... \frac{C^{n}(x)}{n!} = e^{C(x)}\)

怎么理解呢,以8个点的带标号无向图举个例子

8 可以由3 5拼成,但是相乘的时候5 3会再算一次,所以除上\(2!\)

而由4 4 拼成,虽然4 4只算一次,但是1 2 3 4 5 6 7 8 和 5 6 7 8 1 2 3 4本质上一样,所以也要除上\(2!\)

然后我们可以得到

\(C(x) = ln(G(x))\)

怎么求\(ln(G(x))\)呢

设\(F(x) = ln(G(x))\)

两边分别求导

\(F'(x) = \frac{G'(x)}{G(x)}\)

然后再两边积分起来

\(F(x) = \int \frac{G'(x)}{G(x)}\)

求逆元是\(O(n \log n)\)求导\(O(n)\)求积分\(O(n)\)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 130005
#define mo 994711
//#define ivorysi
using namespace std;
typedef unsigned long long int64;
typedef long double db;
typedef unsigned int u32;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
const int MOD = 1004535809,MAXL = 1 << 18;
int W[(1 << 19) + 5],fac[MAXL + 5],inv[MAXL + 5],invfac[MAXL + 5],N; int mul(int a,int b) {
return 1LL * a * b % MOD;
}
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
} struct Poly {
vector<int> p;
Poly() {p.clear();}
friend void NTT(Poly &f,int len,int on) {
f.p.resize(len);
for(int i = 1 , j = len >> 1; i < len - 1; ++i) {
if(i < j) swap(f.p[i],f.p[j]);
int k = len >> 1;
while(j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
for(int h = 2 ; h <= len ; h <<= 1) {
int wn = W[(MAXL + on * MAXL / h) % MAXL];
for(int k = 0 ; k < len ; k += h) {
int w = 1;
for(int j = k ; j < k + h / 2 ; ++j) {
int u = f.p[j],t = mul(w,f.p[j + h / 2]);
f.p[j] = inc(u,t);
f.p[j + h / 2] = inc(u,MOD - t);
w = mul(w,wn);
}
}
}
if(on == -1) {
int InvL = fpow(len,MOD - 2);
for(int i = 0 ; i < len ; ++i) f.p[i] = mul(f.p[i],InvL);
}
}
friend Poly operator * (Poly a,Poly b) {
int L = a.p.size() + b.p.size() - 2;
int t = 1;
while(t <= L) t <<= 1;
a.p.resize(t);b.p.resize(t);
NTT(a,t,1);NTT(b,t,1);
Poly c;
for(int i = 0 ; i < t ; ++i) {
c.p.pb(mul(a.p[i],b.p[i]));
}
NTT(c,t,-1);
int s = c.p.size() - 1;
while(s >= 0 && c.p[s] == 0) {c.p.pop_back();--s;}
return c;
}
friend Poly operator - (Poly a,Poly b) {
Poly c;
int L = max(a.p.size(),b.p.size());
a.p.resize(L);b.p.resize(L);
for(int i = 0 ; i < L ; ++i) c.p.pb(inc(a.p[i],MOD - b.p[i]));
return c;
}
friend Poly operator + (Poly a,Poly b) {
Poly c;
int L = max(a.p.size(),b.p.size());
a.p.resize(L);b.p.resize(L);
for(int i = 0 ; i < L ; ++i) c.p.pb(inc(a.p[i],b.p[i]));
return c;
}
friend Poly Inverse(Poly f,int t) {
f.p.resize(t);
if(t == 1) {
Poly g;g.p.pb(fpow(f.p[0],MOD - 2));
return g;
}
Poly g = Inverse(f,t >> 1);
t *= 2;
NTT(f,t,1);NTT(g,t,1);
Poly r;
for(int i = 0 ; i < t; ++i) {
r.p.pb(inc(mul(2,g.p[i]),MOD - mul(mul(g.p[i],g.p[i]),f.p[i])));
}
NTT(r,t,-1);
t >>= 1;
r.p.resize(t);
--t;
while(t >= 0 && r.p[t] == 0) {r.p.pop_back();--t;}
return r;
}
friend Poly Integral(const Poly &f) {
Poly g;
int L = f.p.size();
g.p.resize(L + 1);
for(int i = 1 ; i <= L ; ++i) {
g.p[i] = mul(f.p[i - 1],inv[i]);
}
return g;
}
friend Poly Derivative(const Poly &f) {
Poly g;
int L = f.p.size();
g.p.resize(L - 1);
for(int i = 0 ; i < L - 1; ++i) {
g.p[i] = mul((i + 1),f.p[i + 1]);
}
return g;
}
friend Poly ln(const Poly &f) {
int t = 1;
while(t <= f.p.size() - 1) t <<= 1;
return Integral(Derivative(f) * Inverse(f,t)); }
}g,f;
void Solve() {
read(N);
W[0] = 1;
W[1] = fpow(3,(MOD - 1) / MAXL);
for(int i = 2 ; i < MAXL ; ++i) W[i] = mul(W[i - 1],W[1]);
fac[0] = 1;invfac[0] = 1;
inv[1] = 1;
for(int i = 2 ; i <= MAXL ; ++i) inv[i] = mul(inv[MOD % i],MOD - MOD / i);
for(int i = 1 ; i <= MAXL ; ++i) fac[i] = mul(fac[i - 1],i);
for(int i = 1 ; i <= MAXL ; ++i) invfac[i] = mul(invfac[i - 1],inv[i]);
g.p.resize(N + 1);
g.p[0] = g.p[1] = 1;
for(int i = 2 ; i <= N ; ++i) {
g.p[i] = mul(fpow(2,1LL * i * (i - 1) / 2 % (MOD - 1)),invfac[i]);
}
f = ln(g);
out(mul(fac[N],f.p[N]));enter;
} int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

【BZOJ】3456: 城市规划(多项式求ln)的更多相关文章

  1. BZOJ 3456: 城市规划 [多项式求逆元 组合数学 | 生成函数 多项式求ln]

    3456: 城市规划 题意:n个点组成的无向连通图个数 以前做过,今天复习一下 令\(f[n]\)为n个点的无向连通图个数 n个点的完全图个数为\(2^{\binom{n}{2}}\) 和Bell数的 ...

  2. BZOJ 3456: 城市规划 [多项式求逆元 DP]

    题意: 求出n个点的简单(无重边无自环)无向连通图数目.方案数mod 1004535809(479 * 2 ^ 21 + 1)即可. n<=130000 DP求方案 g(n) n个点所有图的方案 ...

  3. BZOJ 3456: 城市规划 多项式求逆

    Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.  刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接 ...

  4. bzoj 3456 城市规划 多项式求逆+分治FFT

    城市规划 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1091  Solved: 629[Submit][Status][Discuss] Desc ...

  5. bzoj 3456 城市规划——分治FFT / 多项式求逆 / 多项式求ln

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3456 分治FFT: 设 dp[ i ] 表示 i 个点时连通的方案数. 考虑算补集:连通的方 ...

  6. bzoj 3456 城市规划 —— 分治FFT / 多项式求逆 / 指数型生成函数(多项式求ln)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3456 首先考虑DP做法,正难则反,考虑所有情况减去不连通的情况: 而不连通的情况就是那个经典 ...

  7. bzoj 3456 城市规划 无向简单连通图个数 多项式求逆

    题目大意 求n个点的无向简单连通图个数 做法1 \(f[i]\)表示i个点的无向简单连通图个数 \(g[i]=2^{\frac {i*(i-1)}{2}}\)表示i个点的无向简单图个数(不要求连通) ...

  8. [BZOJ3456]城市规划(生成函数+多项式求逆+多项式求ln)

    城市规划 时间限制:40s      空间限制:256MB 题目描述 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.  刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一 ...

  9. BZOJ3456 城市规划 【多项式求ln】

    题目链接 BZOJ3456 题解 真是一道经典好题,至此已经写了分治\(NTT\),多项式求逆,多项式求\(ln\)三种写法 我们发现我们要求的是大小为\(n\)无向联通图的数量 而\(n\)个点的无 ...

随机推荐

  1. 【刷题】LOJ 6008 「网络流 24 题」餐巾计划

    题目描述 一个餐厅在相继的 \(n\) 天里,每天需用的餐巾数不尽相同.假设第 \(i\) 天需要 \(r_i\) 块餐巾.餐厅可以购买新的餐巾,每块餐巾的费用为 \(P\) 分:或者把旧餐巾送到快洗 ...

  2. 洛谷 T28312 相对分子质量【2018 6月月赛 T2】 解题报告

    T28312 「化学」相对分子质量 题目描述 做化学题时,小\(F\)总是里算错相对分子质量,这让他非常苦恼. 小\(F\)找到了你,请你来帮他算一算给定物质的相对分子质量. 如果你没有学过相关内容也 ...

  3. 三、spring boot 1.5.4 web容器定制(端口号等修改)

    spring boot 默认采用tomcat作为嵌入的web容器 定制方式有三种 1. 2.如下 @Component public class CustomizationBean implement ...

  4. [收藏]:[算法]LRU和LFU的区别

    LRU和LFU是不同的! LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面! LFU是最近最不常用页面置换算法(Least Freque ...

  5. 螺旋队列和hiho1525逃离迷宫3

    我是真调不出错误了! hiho1525逃离迷宫3 #include <stdio.h> #include <stdlib.h> #include <math.h> ...

  6. SQL Server 排名函数( ROW_NUMBER、RANK、DENSE_RANK、NTILE )

    排名函数是Sql Server2005新增的功能,下面简单介绍一下他们各自的用法和区别.我们新建一张Order表并添加一些初始数据方便我们查看效果. CREATE TABLE [dbo].[Order ...

  7. 标准误(Standard Error)

    sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction.htm?courseId=1005269003&utm_campai ...

  8. jdk1.8中获取项目绝对路径和项目路径

    request.getSession().getServletContext().getRealPath("")  获取项目的绝对路径,含着项目的名称. request.getSe ...

  9. 高级篇 KZ002.反射读取注解[未封装]

    创建自定义注解 package com.hanpang.java; /** * 注解说明: 方法的文档注释 * * @Author: 胖先生 * @Create: 2016-04-27 10:29 * ...

  10. .NET面试题系列(三)排序算法

    冒泡排序 , , , , , 7, 2, 4 }; //外层循环控制排序趟数 ; i < arr.Length - ; i++) { //内层循环控制每一趟排序多少次 ; j < arr. ...