BZOJ3456:城市规划——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=3456

求出n个点的简单(无重边无自环)无向连通图数目

模数很熟悉,先敲一个MTT。

然后通过推导式子就做完啦!

我觉得就算怎么讲也没有下面这一位好:http://blog.miskcoo.com/2015/05/bzoj-3456

另外多项式求逆:http://blog.miskcoo.com/2015/05/polynomial-inverse

至少我学到了:当你有个卷积知道答案,求卷积的一项时转换成生成函数再FFT一下就好了。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const ll P=1004535809;
const int G=3;
const int N=5e5+5;
ll qpow(ll a,ll n,ll p){
    ll res=1;
    while(n){
        if(n&1)res=res*a%p;
        a=a*a%p;n>>=1;
    }
    return res;
}
void MTT(ll a[],int n,int on){
    for(int i=1,j=n>>1;i<n-1;i++){
        if(i<j)swap(a[i],a[j]);
        int k=n>>1;
        while(j>=k){j-=k;k>>=1;}
        if(j<k)j+=k;
    }
    for(int i=2;i<=n;i<<=1){
        ll res=qpow(G,(P-1)/i,P);
        for(int j=0;j<n;j+=i){
            ll w=1;
            for(int k=j;k<j+i/2;k++){
                ll u=a[k],t=w*a[k+i/2]%P;
                a[k]=(u+t)%P;
                a[k+i/2]=(u-t+P)%P;
                w=w*res%P;
            }
        }
    }
    if(on==-1){
        ll inv=qpow(n,P-2,P);
        a[0]=a[0]*inv%P;
        for(int i=1;i<=n/2;i++){
            a[i]=a[i]*inv%P;
            if(i!=n-i)a[n-i]=a[n-i]*inv%P;
            swap(a[i],a[n-i]);
        }
    }
}
ll t[N];
void inv(int deg,ll a[],ll b[]){
    if(deg==1){
        b[0]=qpow(a[0],P-2,P);
        return;
    }
    inv((deg+1)>>1,a,b);
    int n=1;
    while(n<(deg<<1))n<<=1;
    for(int i=0;i<deg;i++)t[i]=a[i];
    for(int i=deg;i<n;i++)t[i]=0;
    MTT(t,n,1);MTT(b,n,1);
    for(int i=0;i<n;i++)
        b[i]=b[i]*(2-b[i]*t[i]%P+P)%P;
    MTT(b,n,-1);
    for(int i=deg;i<n;i++)b[i]=0;
}
int n;
ll f[N],g[N],tmp[N],c[N],jc[N],C[N][3];
inline void init(){
    jc[0]=jc[1]=1;C[0][2];
    for(int i=2;i<=n;i++)jc[i]=jc[i-1]*i%P;
    for(int i=1;i<=n;i++)C[i][2]=C[i-1][2]+i-1;
}
int main(){
    scanf("%d",&n);init();
    for(int i=0;i<=n;i++){
        g[i]=qpow(2,C[i][2],P)*qpow(jc[i],P-2,P)%P;
        if(i)c[i]=qpow(2,C[i][2],P)*qpow(jc[i-1],P-2,P)%P;
    }
    int nn=1;
    while(nn<=n)nn<<=1;

    inv(nn,g,tmp);memcpy(g,tmp,sizeof(tmp));

    MTT(g,nn,1);MTT(c,nn,1);
    for(int i=0;i<nn;i++)f[i]=g[i]*c[i]%P;
    MTT(f,nn,-1);

    f[n]=f[n]*jc[n-1]%P;
    printf("%lld\n",f[n]);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

原文地址:https://www.cnblogs.com/luyouqi233/p/9005048.html

时间: 2024-08-04 07:32:59

BZOJ3456:城市规划——题解的相关文章

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

城市规划 时间限制:40s      空间限制:256MB 题目描述 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.  刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.  好了, 这就

BZOJ3456 城市规划 【分治NTT】

题目链接 BZOJ3456 题解 据说这题是多项式求逆 我太弱不会QAQ,只能\(O(nlog^2n)\)分治\(NTT\) 设\(f[i]\)表示\(i\)个节点的简单无向连通图的数量 考虑转移,直接求不好求,我们知道\(n\)个点无向图的数量是\(2^{{n \choose 2}}\)的,考虑用总数减去不连通的 既然图不连通,那么和\(1\)号点联通的点数一定小于\(n\),我们枚举和\(1\)号点所在联通块大小,就可以得到式子: \[f[n] = 2^{{n \choose 2}} - \

BZOJ3456城市规划

BZOJ3456 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; const int mod=1004535809,maxn=1<<18|1; int p[maxn],gn[233]; int n; in

[bzoj3456]城市规划——分治FFT

题目大意: 求n个点的带标号简单无向联通图的数目. 思路: 嗯多项式求逆还不会,到时候会了应该会补吧. 这种和图计数有关的题目一般都是考虑反面计数或者是容斥什么的. 考虑枚举一号点的连通块的大小,然后用总方案数减去这些方案数. 可以得到递推式: \[ f_{i}=2^{i\choose 2}-\sum_{j=1}^{i-1}{i-1\choose j-1}\times f_{j}\times 2^{i-j\choose2} \] 后面的式子可以化为卷积的形式: \[ f_{i}=2^{i\cho

bzoj3456 城市规划

Description 求含有n个点有标号的无向联通图的个数(没有重边),n<=130000 Input 3 Output 4 正解:$分治FFT$/多项式求逆. 并没有权限号,但是某$oj$里有这道题.. 我们考虑递推,$f[i]$表示$i$个点的联通图个数,那么用总数减去不合法的数量. 考虑枚举$1$号点所在的联通块的点数,那么我们可以得到: $f[n]=2^{\binom{n}{2}}-\sum_{i=1}^{n-1}f[i]*\binom{n-1}{i-1}*2^{\binom{n-i}

[bzoj3456]城市规划:多项式,分治

Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案. 好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的

模板记录

NTT: namespace NTT { int n,m,l,r[N]; void NTT(int *a,int f) { for(int i=0;i<n;i++) if(i<r[i]) swap(a[i],a[r[i]]); for(int i=1;i<n;i<<=1) { int wn=q_pow(pr,phi/(i<<1)); if(f==-1) wn=q_pow(wn,mod-2); for(int p=i<<1,j=0;j<n;j+=p

【bzoj3456】城市规划 容斥原理+NTT+多项式求逆

题目描述 求出n个点的简单(无重边无自环)无向连通图数目mod 1004535809(479 * 2 ^ 21 + 1). 输入 仅一行一个整数n(<=130000) 输出 仅一行一个整数, 为方案数 mod 1004535809. 样例输入 3 样例输出 4 题解 容斥原理+NTT+多项式求逆 设 $f_i$ 表示 $i$ 个点的简单无向连通图的数目,$g_i$ 表示 $i$ 个点的简单无向图的数目. 根据定义得 $g_i=2^{\frac{n(n-1}2}$ . 对于 $f_i$ ,考虑容斥

【bzoj3456】城市规划(多项式求逆+dp)

Description 求\(~n~\)个点组成的有标号无向连通图的个数.\(~1 \leq n \leq 13 \times 10 ^ 4~\). Solution 这道题的弱化版是poj1737, 其中\(n \leq 50\), 先来解决这个弱化版的题.考虑\(~dp~\),直接统计答案难以入手,于是考虑容斥.显然有,符合条件的方案数\(=\)所有方案数\(-\)不符合条件的方案数,而这个不符合条件的方案数就是图没有完全联通的情况.设\(~dp_i~\)表示\(~i~\)个点组成的合法方案