zoukankan      html  css  js  c++  java
  • 【bzoj3456】 城市规划

    题目

    一句话题意,无向连通图计数

    技不如人,甘拜下风

    (f_i)表示(i)个节点构成的无向连通图数量

    之后。。。之后就不会了

    于是抄题解

    考虑容斥

    [f_i=t_i-sum_{j=1}^{i-1}inom{i-1}{j-1}f_jt_{i-j} ]

    (t_i)表示(i)个节点构成的无向图数量,实际上(t_i=2^{frac{i(i-1)}{2}}),就是每一条边都有存在或者不存在两种选择,这样显然不能保证联通

    上面那个柿子的含义就是先算上所有情况,减掉不连通的,先选择(j-1)个点和(1)号节点联通,之后剩下的(i-j)个节点自己随便连去吧,由于两部分没有联通,所以整张图一定不会联通

    我们觉得让(f_i)在外面孤独的待着不太好,于是我们可以把(f_i)放进来

    就有

    [t_i-sum_{j=1}^ninom{i-1}{j-1}f_jt_{i-j} ]

    因为当(j=i)的时候,(inom{i-1}{j-1}=t_{i-j}=1),所以可以把(f_i)放进来

    拆组合数

    [t_i=sum_{j=1}^nfrac{(i-1)!f_jt_{i-j}}{(j-1)!(i-j)!} ]

    ((i-1)!)真多余,让它出来

    [frac{t_i}{(i-1)!}=sum_{j=1}^nfrac{f_j}{(j-1)!} imes frac{t_{i-j}}{(i-j)!} ]

    考虑生成函数,设

    [G(x)=frac{t_x}{(x-1)!},F(x)=frac{f_i}{(i-1)!},T(x)=frac{t_x}{x!} ]

    于是我们直观发现应该写成

    [G(x)=F(x) imes T(x) ]

    于是(F(x)=frac{G(x)}{T(x)}),多项式求逆就好了

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    const int maxn=262144+1005;
    const LL mod=1004535809;
    LL G[2];
    LL K[maxn],T[maxn],C[maxn];
    LL fac[maxn],t[maxn],pow[maxn],A[maxn],R[maxn],B[maxn],ifac[maxn];
    int rev[maxn],n,len;
    inline LL ksm(LL a,LL b) {LL S=1;while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;}
    inline void NTT(LL *f,int o) {
    	for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
    	for(re int i=2;i<=len;i<<=1) {
    		int ln=i>>1;LL og1=ksm(G[o],(mod-1)/i);
    		for(re int l=0;l<len;l+=i) {
    			LL t,og=1;
    			for(re int x=l;x<l+ln;x++) {
    				t=(og*f[ln+x])%mod;
    				f[ln+x]=(f[x]-t+mod)%mod;
    				f[x]=(f[x]+t)%mod;
    				og=(og*og1)%mod;
    			}
    		}
    	}
    	if(!o) return;
    	LL inv=ksm(len,mod-2);
    	for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod;
    }
    inline void mul(int n,LL *A,LL *B) {
    	len=1;while(len<n+n) len<<=1;
    	for(re int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
    	NTT(A,0),NTT(B,0);for(re int i=0;i<len;i++) A[i]=(A[i]*B[i])%mod;
    	NTT(A,1);for(re int i=n;i<len;i++) A[i]=0;
    }
    inline void Inv(int n,LL *A,LL *B) {
    	if(n==1) {B[0]=ksm(A[0],mod-2);return;}
    	Inv((n+1)>>1,A,B);
    	memset(C,0,sizeof(C));memset(T,0,sizeof(T));memset(K,0,sizeof(K));
    	for(re int i=0;i<n;i++) C[i]=K[i]=B[i],T[i]=A[i];
    	mul(n,C,K);mul(n,C,T);
    	for(re int i=0;i<n;i++) B[i]=(2ll*B[i]-C[i]+mod)%mod;
    }
    int main() {
    	G[0]=3,G[1]=ksm(3,mod-2);
    	scanf("%d",&n);
    	pow[0]=1;for(re int i=1;i<=n;i++) pow[i]=(pow[i-1]*2ll)%mod;
    	fac[0]=1;for(re int i=1;i<=n;i++) fac[i]=(fac[i-1]*(LL)i)%mod;
    	t[0]=1;t[1]=1;for(re int i=2;i<=n;i++) t[i]=(t[i-1]*pow[i-1])%mod;
    	ifac[n]=ksm(fac[n],mod-2);
    	for(re int i=n-1;i>=0;--i) ifac[i]=(ifac[i+1]*(LL)(i+1))%mod;
    	for(re int i=0;i<=n;i++) B[i]=t[i]*ifac[i]%mod;
    	for(re int i=1;i<=n;i++) A[i]=t[i]*ifac[i-1]%mod;
    	Inv(n+1,B,R);mul(n+1,A,R);
    	printf("%lld
    ",A[n]*fac[n-1]%mod);
    	return 0;
    }
    
  • 相关阅读:
    Gitlab 11.0.3配置LDAP
    IntelliJ IDEA快速创建属性字段的get和set方法
    解决Maven引用POI的依赖,XSSFWorkbook依旧无法使用的问题
    解决方案看起来是受源代码管理,但无法找到它的绑定信息。保存解决方案的源代码管理设置的MSSCCPRJ.SCC文件或其他项可能己被删除。
    IntelliJ IDEA开发工具println报错的解决方法
    Eclipse开发工具printf打印方法提示报错的解决方法
    Java基础学习总结一(Java语言发展历史、JDK下载安装以及配置环境变量)
    浅谈JavaScript之function用括号包起来
    讲解JavaScript两个圆括号、自调用和闭包函数
    Visual Studio Code使用Open In Browser打开的是记事本
  • 原文地址:https://www.cnblogs.com/asuldb/p/10550150.html
Copyright © 2011-2022 走看看