[bzoj3456]城市规划

xjr_01 xjr_01     2022-10-16     274

关键词:

[BZOJ3456]城市规划

试题描述

刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.

刚才说过, 阿狸的国家有 (n) 个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.

好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出 (n) 个点的简单(无重边无自环)无向连通图数目.

由于这个数字可能非常大, 你只需要输出方案数 (mod 1004535809(479 imes 2 ^ {21} + 1)) 即可.

输入

仅一行一个整数 (n(le 130000))

输出

仅一行一个整数, 为方案数 (mod 1004535809).

输入示例

3

输出示例

4

数据规模及约定

对于 (100\%) 的数据, (n le 130000)

题解

(f(n)) 表示 (n) 个点的带标号简单无向连通图的个数,(g(n)) 表示 (n) 个点带标号简单无向图的个数,则显然有 (g(n) = 2^{C_n^2})

(f(n)) 的计算是一个经典的容斥,它等于无向图个数减去不连通的个数,不连通图的个数可以通过枚举“和节点 (1) 在同一个连通块的点数”来计算,具体地:

[ f(n) = g(n) - sum_{i=1}^{n-1} C_{n-1}^{i-1} cdot f(i) cdot g(n-i) ]

就是先确定哪 (i-1) 个点与 (1) 在同一个连通块中(组合数),然后连同部分的个数就是 (f(i)),剩下的部分随意连(即 (g(n-i)))。

把组合数展开得到

[ f(n) = g(n) - sum_{i=1}^{n-1} frac{(n-1)!}{(i-1)!(n-i)!} cdot f(i) cdot g(n-i) f(n) = (n-1)! cdot left[ frac{g(n)}{(n-1)!} - sum_{i=1}^{n-1} frac{f(i)}{(i-1)!} cdot frac{g(n-i)}{(n-i)!} ight] \frac{f(n)}{(n-1)!} = frac{g(n)}{(n-1)!} - sum_{i=1}^{n-1} frac{f(i)}{(i-1)!} cdot frac{g(n-i)}{(n-i)!} ]

那么定义 (F(x), G(x), G_1(x)) 如下:

[ F(x) = sum_{i=1}^n frac{f(i)}{(i-1)!} x^i G(x) = sum_{i=1}^n frac{g(i)}{i!} x^i G_1(x) = sum_{i=1}^n frac{g(i)}{(i-1)!} x^i ]

那么有

[ F(x) = G_1(x) - F(x) cdot G(x) F(x) = frac{G_1(x)}{G(x) + 1} ]

最后输出时不要忘了把 ((n-1)!) 乘回来!

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 262144
#define MOD 1004535809
#define Groot 3
#define LL long long

int Pow(int a, int b) {
    int ans = 1, t = a;
    while(b) {
        if(b & 1) ans = (LL)ans * t % MOD;
        t = (LL)t * t % MOD; b >>= 1;
    }
    return ans;
}
int _Pow(int a, LL b) {
    int ans = 1, t = a;
    while(b) {
        if(b & 1) ans = (LL)ans * t % MOD;
        t = (LL)t * t % MOD; b >>= 1;
    }
    return ans;
}

int brev[maxn];
void FFT(int *a, int len, int tp) {
    int n = 1 << len;
    rep(i, 0, n - 1) if(i < brev[i]) swap(a[i], a[brev[i]]);
    rep(i, 1, len) {
        int wn = Pow(Groot, MOD - 1 >> i);
        if(tp < 0) wn = Pow(wn, MOD - 2);
        for(int j = 0; j < n; j += 1 << i) {
            int w = 1;
            rep(k, 0, (1 << i >> 1) - 1) {
                int la = a[j+k], ra = (LL)w * a[j+k+(1<<i>>1)] % MOD;
                a[j+k] = (la + ra) % MOD;
                a[j+k+(1<<i>>1)] = (la - ra + MOD) % MOD;
                w = (LL)w * wn % MOD;
            }
        }
    }
    if(tp < 0) {
        int invn = Pow(n, MOD - 2);
        rep(i, 0, n - 1) a[i] = (LL)a[i] * invn % MOD;
    }
    return ;
}

void Mul(int *A, int *B, int n, int m, bool recover = 0) {
    int N = 1, len = 0;
    while(N <= n + m) N <<= 1, len++;
    rep(i, 0, N - 1) brev[i] = (brev[i>>1] >> 1) | ((i & 1) << len >> 1);
    FFT(A, len, 1); FFT(B, len, 1);
    rep(i, 0, N - 1) A[i] = (LL)A[i] * B[i] % MOD;
    FFT(A, len, -1); if(recover) FFT(B, len, -1);
    return ;
}

int tmp[maxn];
void inverse(int *f, int *g, int n) {
    if(n == 1) return (void)(f[0] = Pow(g[0], MOD - 2));
    inverse(f, g, n + 1 >> 1);
    rep(i, 0, n - 1) tmp[i] = g[i];
    int N = 1, len = 0;
    while(N < (n << 1)) N <<= 1, len++;
    rep(i, 0, N - 1) brev[i] = (brev[i>>1] >> 1) | ((i & 1) << len >> 1);
    rep(i, n + 1 >> 1, N - 1) f[i] = 0;
    rep(i, n, N - 1) tmp[i] = 0;
    FFT(f, len, 1); FFT(tmp, len, 1);
    rep(i, 0, N - 1) f[i] = ((LL)f[i] * (2ll - (LL)tmp[i] * f[i] % MOD) % MOD + MOD) % MOD;
    FFT(f, len, -1);
    return ;
}

int fac[maxn], ifac[maxn];
void init(int n) {
    ifac[1] = 1;
    rep(i, 2, n) ifac[i] = (LL)(MOD - MOD / i) * ifac[MOD%i] % MOD;
    fac[0] = ifac[0] = 1;
    rep(i, 1, n) fac[i] = (LL)fac[i-1] * i % MOD, ifac[i] = (LL)ifac[i-1] * ifac[i] % MOD;
    return ;
}

LL C2(int n) { return (LL)n * (n - 1) >> 1; }

int G[maxn], G1[maxn], iG[maxn];

int main() {
    int n = read();
    init(n);
    
    rep(i, 1, n) {
        int t = _Pow(2, C2(i));
        G[i] = (LL)t * ifac[i] % MOD;
        G1[i] = (LL)t * ifac[i-1] % MOD;
    }
    G[0] = 1;
    inverse(iG, G, n + 1);
    Mul(G1, iG, n, n);
    
    printf("%lld
", (LL)G1[n] * fac[n-1] % MOD);
    
    return 0;
}

[bzoj3456]城市规划

[BZOJ3456]城市规划试题描述刚刚解决完电力网络的问题,阿狸又被领导的任务给难住了.刚才说过,阿狸的国家有(n)个城市,现在国家需要在某些城市对之间建立一些贸易路线,使得整个国家的任意两个城市都直接或间接的连通.为了省... 查看详情

bzoj3456:城市规划——题解(代码片段)

https://www.lydsy.com/JudgeOnline/problem.php?id=3456求出n个点的简单(无重边无自环)无向连通图数目模数很熟悉,先敲一个MTT。然后通过推导式子就做完啦!我觉得就算怎么讲也没有下面这一位好:http://blog.miskcoo.com/2015/05/bzoj-3456另外多项... 查看详情

[bzoj3456]城市规划

看来我得恶补组合数学了...先回忆一下指数生成函数乘积的性质:若$\beginalign*A_e(x)=\sum\limits_n=0^\inftya_n\dfracx^nn!,B_e(x)=\sum\limits_n=0^\inftyb_n\dfracx^nn!\endalign*$,那么$\beginalign*A_e(x)B_e(x)=\sum\limit 查看详情

bzoj3456:城市规划多项式求逆

3456:城市规划TimeLimit:40Sec  MemoryLimit:256MBSubmit:798  Solved:451[Submit][Status][Discuss]Description 刚刚解决完电力网络的问题,阿狸又被领导的任务给难住了. 刚才说过,阿狸的国家有n个城市,现在国家需要在某些城市对之... 查看详情

bzoj3456城市规划分治ntt

题目链接BZOJ3456题解据说这题是多项式求逆我太弱不会QAQ,只能\(O(nlog^2n)\)分治\(NTT\)设\(f[i]\)表示\(i\)个节点的简单无向连通图的数量考虑转移,直接求不好求,我们知道\(n\)个点无向图的数量是\(2^n\choose2\)的,考虑用总数减去不... 查看详情

[bzoj3456]城市规划

【题目大意】求含有n个点有标号的无向联通图的个数(没有重边),n<=130000方案数对1004535809(479*2^21+1)取模样例输入3样例输出4我们考虑递推,$f[i]$表示$i$个点的联通图个数,那么用总数减去不合法的数量。考虑枚举$1$号点所... 查看详情

bzoj3456城市规划

Description求含有n个点有标号的无向联通图的个数(没有重边),n<=130000Input3Output4 正解:$分治FFT$/多项式求逆。并没有权限号,但是某$oj$里有这道题。。 我们考虑递推,$f[i]$表示$i$个点的联通图个数,那么用总数减去... 查看详情

bzoj3456:城市规划ntt+多项式求逆

参考:http://blog.miskcoo.com/2015/05/bzoj-3456首先推出递推式(上面的blog讲的挺清楚的),大概过程是正难则反,设g为n个点的简单(无重边无自环)无向图数目,显然边数是\(C_n^2\),所以\(g(n)=2^C_n^2\),那么f[n]=g[n]-n个点的简单(无重边无自... 查看详情

bzoj3456城市规划多项式求逆+分治fft(代码片段)

城市规划TimeLimit: 40Sec  MemoryLimit: 256MBSubmit: 1091  Solved: 629[Submit][Status][Discuss]Description 刚刚解决完电力网络的问题,阿狸又被领导的任务给难住了. 刚才说过,阿狸的国家有n个城市,现在国家 查看详情

bzoj3456城市规划(多项式求逆+dp)(代码片段)

Description求(~n~)个点组成的有标号无向连通图的个数。(~1leqnleq13 imes10^4~).Solution这道题的弱化版是poj1737,其中(nleq50),先来解决这个弱化版的题。考虑(~dp~),直接统计答案难以入手,于是考虑容斥。显然有,符合条件的方案数(=)所... 查看详情

bzoj3456城市规划容斥原理+ntt+多项式求逆

题目描述求出n个点的简单(无重边无自环)无向连通图数目mod1004535809(479*2^21+1).输入仅一行一个整数n(<=130000)输出仅一行一个整数,为方案数mod1004535809.样例输入3样例输出4题解容斥原理+NTT+多项式求逆设$f_i$表示$i$个点的简单无向... 查看详情

[bzoj3456]城市规划(生成函数+多项式求逆+多项式求ln)(代码片段)

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

bzoj3456城市规划

求n个点简单无向连通图个数,膜$1004535809$(是一个质数,原根是$3$)$nleq130000$sol:推式子的方法...应该到处都有记录一下指数生成函数(EGF)的做法先设$g(x)$为n个点简单无向图的EGF,可以知道$g(x)=sumlimits_i=0^infty2^inomi2 imesfracx^ii!$然... 查看详情

[bzoj3456]城市规划——分治fft(代码片段)

题目大意:求n个点的带标号简单无向联通图的数目。思路:嗯多项式求逆还不会,到时候会了应该会补吧。这种和图计数有关的题目一般都是考虑反面计数或者是容斥什么的。考虑枚举一号点的连通块的大小,然后用总方案数... 查看详情

bzoj34563456:城市规划(ntt+多项式求逆)

   3456:城市规划TimeLimit: 40Sec  MemoryLimit: 256MBSubmit: 658  Solved: 364Description 刚刚解决完电力网络的问题,阿狸又被领导的任务给难住了. 刚才说过,阿狸的国家有n个城市,现在国家需要在某些... 查看详情

bzoj3456(代码片段)

有两种推导方法:第一种:设状态$f(i)$表示有$i$个点的无向连通图个数,$g(i)$表示有$i$个点的无向图个数,那么显然$f(n)$即为我们所求,而$g(i)=2^\fraci(i-1)2$于是写出一个递推:枚举$1$号点所在的连通块,可得:$g(n)=\sum_i=1^nC_n-1^i-... 查看详情

bzoj3456ntt图的计数容斥

思路:RT懒得写了//BySiriusRen#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;typedeflonglongll;constintN=(1<<18)+5,mod=1004535809;inttmp[N],R[N],fac[N],A[N],B[N] 查看详情

bzoj3456

分治+ntt设dp[i]表示i个点的图联通的方案数那么考虑dp,利用容斥,总-不符合,枚举j=1->i-1,然后考虑不符合,那么考虑和1联通的连通块,剩下的不和1连通,那么dp[i]=2^t(i)-∑j=1->i-1dp[j]*C(i-1,j-1)*2^t(i-j)就是t(i)表示i个点的图的边... 查看详情