题解

在我写过分治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. Emacs_快捷键列表

    Emacs_快捷键列表 emacs -nw 以终端模式运行emacsLC_CTYPE=zh_CN.UTF-8 emacs C = Control M = Meta = Alt | EscAlt 可以粘 ...

  2. oracle 配置本地Net服务

    1.查看当前数据库名字(前提是已经创建了),先前忘记数据库实例名乱输,然后创建一直失败 开始,程序,Oracle_xxxx_home1 ,配置和移植工具, Database Configuration ...

  3. MT【201】折线计数

    甲乙两人参加竞选,结果甲得n票,乙得m票(n > m) . 则在唱票过程中,甲的累计票数始终超过乙的累计票数的概率是_____________. 答案:$\dfrac{n-m}{n+m}$

  4. 32个Python爬虫实战项目,满足你的项目慌

    爬虫项目名称及简介 一些项目名称涉及企业名词,小编用拼写代替 1.[WechatSogou]- weixin公众号爬虫.基于weixin公众号爬虫接口,可以扩展成其他搜索引擎的爬虫,返回结果是列表,每 ...

  5. 沉迷AC自动机无法自拔之:[UVALive 4126] Password Suspects

    图片加载可能有点慢,请跳过题面先看题解,谢谢 一看到这么多模式串就非常兴奋,又是\(AC\)自动机 题目就是要求:经过 \(n\) 个节点,把所有单词都遍历一遍的方案数,和那道题差不多嘛 所以这样设: ...

  6. 【Luogu4609】建筑师(第一类斯特林数,组合数学)

    [Luogu4609]建筑师(组合数学) 题面 洛谷 题解 首先发现整个数组一定被最高值切成左右两半,因此除去最高值之后在左右分开考虑. 考虑一个暴力\(dp\) ,设\(f[i][j]\)表示用了\ ...

  7. 【转】ubuntu 12.04下如何开启 NFS 服务 & 设置

    在嵌入式Linux开发中,利用NFS服务从开发板访问Linux主机是个高效&方便的调试方法,在程序调试过程中可以避免多次下载程序到开发板.但这需要在Linux主机上首先开通NFS服务. 以ub ...

  8. hdu5449 Robot Dog (树形dp+倍增lca)

    (警告:本篇博客包含大量人类本质内容) 先处理出来lca,然后就只需要知道从每个点到他的父亲.和从他的父亲到这个点的期望时间就可以了 我们设f[x]为x到他父亲的期望时间:g[x]为从x的父亲到x的期 ...

  9. luogu1083 [NOIp2012]借教室 (二分答案+差分)

    先二分一个答案x,然后通过差分来看有没有不满足的 #include<bits/stdc++.h> #define pa pair<int,int> #define lowb(x ...

  10. Pair_2测试与优化

    # Pair_2测试与优化 211606316李震 21160305胡彤 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分 ...