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

    传送门

    感觉这个题是真的神仙啊,思路是真的难想

    首先设(f(i))(i)个点的无向连通图个数,然后设(g(i))(i)个点的图的个数(注意,此处不一定联通)

    那么我们考虑枚举(1)号点所在的联通块的大小

    显然有

    [g(n)=sum_{i=1}^nf(i)inom{n-1}{i-1}g(n-i)\ ]

    考虑到

    [g(n)=2^{inom{n}{2}}\ ]

    所以有

    [sum_{i=1}^{n}f(i)inom{n-1}{i-1}2^{inom{n-i}{2}}=2^{inom{n}{2}}\ ]

    后面的应该就很好推了,这个题主要的难点是考虑枚举(1)所在的联通块大小

    后面还是套路,把组合数拆开

    [sum_{i=1}^nf(i)frac{(n-1)!}{(n-i)!(i-1)!}2^{inom{n-i}{2}}=2^{inom{n}{2}}\ ]

    把相同项移到一起去

    [sum_{i=1}^nfrac{f(i)}{(i-1)!}frac{2^{inom{n-i}{2}}}{(n-i)!}=frac{2^{inom{n}{2}}}{(n-1)!}\ ]

    这个式子已经很眼熟了,再设

    [A(x)=sum_{i=0}frac{f(i)}{(i-1)!}x^i\ B(x)=sum_{i=0}frac{2^{inom{i}{2}}}{i!}x^i\ C(x)=sum_{i=0}frac{2^{inom{i}{2}}}{(i-1)!}x^i\ ]

    很显然有

    [C(x)=A(x)B(x)\ A(x)=C(x)B(x)^{-1} ]

    然后就可以多项式求逆+NTT了

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cmath>
    using namespace std;
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    #define rg register
    const int maxn=4e5+10,mod=1004535809,g=3,gi=334845270,modd=mod-1;
    int n,a[maxn],b[maxn],c[maxn],m,fac[maxn],inv[maxn],len,ans,r[maxn],mx;
    int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
    int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    int mi(int a,int b){
        int ans=1;
        while(b){
            if(b&1)ans=mul(ans,a);
            b>>=1,a=mul(a,a);
        }
        return ans;
    }
    void ntt(int *a,int n,int f){
        for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[i],a[r[i]]);
        for(rg int i=1;i<n;i<<=1){
            int wn=mi(f?g:gi,(mod-1)/(i<<1));
            for(rg int j=0;j<n;j+=i<<1){
                int w=1;
                for(rg int k=0;k<i;k++){
                    int x=a[j+k],y=mul(w,a[i+j+k]);
                    a[j+k]=add(x,y),a[j+k+i]=del(x,y),w=mul(w,wn);
                }
            }
        }
        if(f)return ;int inv=mi(n,mod-2);
        for(rg int i=0;i<n;i++)a[i]=mul(a[i],inv);
    }
    void get_inv(int *b,int n){
        if(n==1)return b[0]=mi(a[0],mod-2),void();
        get_inv(b,(n+1)>>1);
        m=n;len=0;
        for(n=1;n<=m<<1;n<<=1)len++;
        for(rg int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
        for(rg int i=0;i<n;i++)c[i]=a[i];
        for(rg int i=m;i<n;i++)c[i]=0;
        ntt(b,n,1),ntt(c,n,1);
        for(rg int i=0;i<n;i++)b[i]=del(mul(2,b[i]),mul(mul(c[i],b[i]),b[i]));
        ntt(b,n,0);
        for(rg int i=m;i<n;i++)b[i]=0;
    }
    int main(){
        read(n);fac[0]=inv[0]=1;
        for(rg int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
        inv[n]=mi(fac[n],mod-2);
        for(rg int i=n-1;i;i--)inv[i]=mul(inv[i+1],i+1);
        for(rg int i=0;i<=n;i++)a[i]=mul(mi(2,1ll*i*(i-1)/2%modd),inv[i]);
        get_inv(b,n);n++;
        for(rg int i=1;i<n;i++)c[i]=mul(mi(2,1ll*i*(i-1)/2%modd),inv[i-1]);
        m=n;len=0;
        for(n=1;n<=m<<1;n<<=1)len++;
        for(rg int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
        ntt(b,n,1),ntt(c,n,1);
        for(rg int i=0;i<n;i++)b[i]=mul(b[i],c[i]);
        ntt(b,n,0);
        printf("%d
    ",mul(b[m-1],fac[m-2]));
    }
    
    
  • 相关阅读:
    java栈的实现
    浅谈JSON
    Java反射机制及IoC原理
    ApplicationContext之getBean方法详解
    web.xml中的contextConfigLocation的作用
    ApplicationContext的名称解释
    spring boot如何处理异步请求异常
    screen工具实现简单分析
    SO_LINGER选项的作用和意义
    gcc的异常处理机制
  • 原文地址:https://www.cnblogs.com/lcxer/p/10767913.html
Copyright © 2011-2022 走看看