zoukankan      html  css  js  c++  java
  • 洛谷4841:城市规划

    洛谷4841:城市规划

    题意:

    (n)个点的简单(无重边无自环)有标号无向连通图数目。

    思路:

    (f(n))为点数为(n)的无向连通图的数量,(g(n))为点数为(n)的无向图的数量,可以知道:

    [g(n)=2^{C_n^2} ]

    可以这么理解,(n)个点中取两个点连边,一共有(C_n^2)种,每个边存在连或不连两种可能。

    同时有:

    [g(n)=sum_{i=1}^nC_{n-1}^{i-1}f(i) imes g(n-i) ]

    这个可以这么理解,对于一号点,枚举它所在的连通块中有多少个点。

    代入(g(n))可得:

    [2^{C_n^2}=sum_{i=1}^nC_{n-1}^{i-1}f(i)2^{C_{n-i}^2} ]

    化简一下:

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

    [F(x)=sum_{n=1}^{+infin}frac{f(n)}{(n-1)!}x^n\G(x)=sum_{n=0}^{+infin}frac{2^{C_n^2}}{n!}x^n\H(x)=sum_{n=1}^{+infin}frac{2^{C_n^2}}{(n-1)!}x^n ]

    那么有:

    [Fequiv H*G^{-1}(mod x^{n+1}) ]

    NTT+多项式求逆求解。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 6e5+10;
    
    const ll mod = 1004535809;
    const int G = 3;
    int n;
    
    ll inv[maxn];   //逆元
    ll fiv[maxn];   //逆元的阶乘
    ll g1[maxn], g2[maxn], g3[maxn];
    
    ll qmi(ll a, ll b)
    {
        ll res = 1;
        while(b)
        {
            if(b&1) res = (res*a)%mod;
            b >>= 1;
            a = (a*a)%mod;
        } return res%mod;
    }
    
    int limit, len, rev[maxn];
    void NTT(ll *c, int op)
    {
        for(int i = 1; i <= limit; i++)
            if(i < rev[i]) swap(c[i], c[rev[i]]);
    
        for(int mid = 1; mid < limit; mid <<= 1)
        {
            ll gn = qmi(G, (mod-1)/(mid<<1));
            if(op == -1) gn = qmi(gn, mod-2);
            for(int j = 0, R = mid<<1; j < limit; j += R)
            {
                ll g = 1;
                for(int k = 0; k < mid; k++, g = (g*gn)%mod)
                {
                    ll x = c[j+k], y = g*c[j+k+mid]%mod;
                    c[j+k] = (x+y)%mod;
                    c[j+k+mid] = (x-y+mod)%mod;
                }
            }
        }
        if(op == 1) return;
        ll inv = qmi(limit, mod-2);
        for(int i = 0; i <= limit; i++) c[i] = c[i]*inv%mod;
    }
    
    ll tmp[maxn];
    void get_inv(ll *a, ll *b, int deg)
    {
    	if(deg == 1)
    	{
    		b[0] = qmi(a[0], mod-2);
    		return;
    	}
    	get_inv(a, b, (deg+1)>>1);
    
    	len = 0, limit = 1;
    	while(limit <= (deg+deg)) limit <<= 1, len++;
    
    	for(int i = 1; i <= limit; i++)
    		rev[i] = (rev[i>>1]>>1)|((i&1)<<(len-1));
    
    	for(int i = 0; i < deg; i++) tmp[i] = a[i];
    	for(int i = deg; i <= limit; i++) tmp[i] = 0;
    
    	NTT(tmp, 1), NTT(b, 1);
    	for(int i = 0; i <= limit; i++)
    		b[i] = 1ll*(2-1ll*tmp[i]*b[i]%mod+mod)%mod*b[i]%mod;
    	NTT(b, -1);
    	for(int i = deg; i <= limit; i++) b[i] = 0;
    }
    
    int main()
    {
        scanf("%d", &n); n += 1;
        fiv[0]=fiv[1]=inv[0]=inv[1]=1;
        for(int i = 2; i <= n; i++)
        {
            inv[i] = (ll(mod-mod/i)*inv[mod%i])%mod;
            fiv[i] = fiv[i-1]*inv[i]%mod;
        }
    
        g3[0] = 1;
        for(ll i = 1; i < n; i++)
        {
            ll tmp = qmi(2, (i*(i-1)/2)%(mod-1))%mod;//欧拉降幂
            g1[i] = tmp*fiv[i-1]%mod;
            g3[i] = tmp*fiv[i]%mod;
        }
        get_inv(g3, g2, n);
    
        NTT(g1, 1); NTT(g2, 1);
    
        for(int i = 0; i <= limit; i++) g1[i] = g1[i]*g2[i]%mod;
    
        NTT(g1, -1);
    
        ll ans = g1[n-1]%mod*qmi(fiv[n-2], mod-2)%mod;
        cout << ans << endl;
        return 0;
    }
    
    
  • 相关阅读:
    文件路径选择中的三态逻辑
    .net版本号
    使用MSBuild编译vs多个解决方案
    CEF截图
    使用SharpZIpLib写的压缩解压操作类
    软件试用期设置
    list转datatable
    excel 导入
    网站登录简单验证码
    UEditor编辑器
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12848328.html
Copyright © 2011-2022 走看看