zoukankan      html  css  js  c++  java
  • 有标号的二分图计数 [生成函数 多项式]

    有标号的二分图计数

    题目也在COGS上

    [HZOI 2015]有标号的二分图计数 I

    [HZOI 2015]有标号的二分图计数 II

    [HZOI 2015]有标号的二分图计数 III


    I

    求n个点的二分图(可以不连通)的个数。(n le 10^5)

    其中二分图进行了黑白染色,两个二分图不同:边不同 或 点的颜色不同

    水题啊,只有黑白之间连边。

    [sum_{k=0}^n inom{n}{k} 2^{k(n-k)} ]


    II

    求n个点的二分图(可以不连通)的个数。(n le 10^5)

    不能简单的除以2,问题在于有的黑白之间不连边

    i个连通块,贡献就是(2^i)

    DP (f(n,i))表示n个点i个连通块的二分图个数,(O(n^3))


    考虑生成函数

    (S(x))表示上道题,(F(x))表示本题

    还是不好做,因为都与连通块有关,引入(H(x))表示单个连通块!

    [S(x) = sum_{i ge 0} frac{2^i cdot H(x)^i}{i!} \ F(x) = sum_{i ge 0} frac{H(x)^i}{i!} = sqrt{S(x)}\ ]

    多项式开根即可



    III

    求n个点的二分图(必须连通)的个数。(n le 10^5)

    就是(H(x))

    就是(frac{1}{2} ln S(x))



    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+5, P = 998244353;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    ll Pow(ll a, int b) {
    	ll ans = 1;
    	for(; b; b>>=1, a=a*a%P)
    		if(b&1) ans=ans*a%P;
    	return ans;
    }
    int n;
    ll inv[N], fac[N], facInv[N];
    inline ll C(int n, int m) {return fac[n] * facInv[m] %P * facInv[n-m] %P;}
    int main() {
    	freopen("QAQ_bipartite_one.in", "r", stdin);
    	freopen("QAQ_bipartite_one.out", "w", stdout);
    	//freopen("in", "r", stdin);
    	n = read();
    	inv[1] = fac[0] = facInv[0] = 1;
    	for(int i=1; i<=n; i++) {
    		if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P;
    		fac[i] = fac[i-1] * i %P;
    		facInv[i] = facInv[i-1] * inv[i] %P;
    	}
    	ll ans = 0;
    	for(int k=0; k<=n; k++) ans = (ans + C(n, k) * Pow(2, (ll) k * (n-k) % (P-1))) %P;
    	printf("%lld
    ", ans);
    }
    
    

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N = (1<<18) + 5, P = 998244353, qr2 = 116195171, inv2 = (P+1)/2;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    ll Pow(ll a, int b) {
    	ll ans = 1;
    	for(; b; b >>= 1, a = a * a %P)
    		if(b & 1) ans = ans * a %P;
    	return ans;
    }
    
    namespace fft {
    	int rev[N];
    	void dft(int *a, int n, int flag) { 
    		int k = 0; while((1<<k) < n) k++;
    		for(int i=0; i<n; i++) {
    			rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
    			if(i < rev[i]) swap(a[i], a[rev[i]]);
    		}
    		for(int l=2; l<=n; l<<=1) {
    			int m = l>>1;
    			ll wn = Pow(3, flag == 1 ? (P-1)/l : P-1-(P-1)/l);
    			for(int *p = a; p != a+n; p += l) 
    				for(int k=0, w=1; k<m; k++, w = w*wn%P) {
    					int t = (ll) w * p[k+m] %P;
    					p[k+m] = (p[k] - t + P) %P;
    					p[k] = (p[k] + t) %P;
    				}
    		}
    		if(flag == -1) {
    			ll inv = Pow(n, P-2);
    			for(int i=0; i<n; i++) a[i] = a[i] * inv %P;
    		}
    	}
    
    	void sqr(int *a, int n) {
    		dft(a, n, 1);
    		for(int i=0; i<n; i++) a[i] = (ll) a[i] * a[i] %P;
    		dft(a, n, -1);
    	}
    
    	void inverse(int *a, int *b, int l) {
    		static int t[N];
    		if(l == 1) {b[0] = Pow(a[0], P-2); return;}
    		inverse(a, b, l>>1);
    		int n = l<<1;
    		for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0; 
    		dft(t, n, 1); dft(b, n, 1);
    		for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P;
    		dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
    	}
    
    	void sqrt(int *a, int *b, int l) {
    		static int t[N], ib[N];
    		if(l == 1) {b[0] = 1; return;}
    		sqrt(a, b, l>>1);
    		int n = l<<1;
    		for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = ib[i] = ib[i+l] = 0;
    		inverse(b, ib, l);
    		dft(t, n, 1); dft(b, n, 1); dft(ib, n, 1);
    		for(int i=0; i<n; i++) b[i] = (ll) inv2 * (b[i] + (ll) t[i] * ib[i] %P) %P;
    		dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
    	}
    }
    
    int n, a[N], f[N], len;
    ll inv[N], fac[N], facInv[N], mi[N];
    int main() {
    	//freopen("in", "r", stdin);
    	freopen("QAQ_bipartite_two.in", "r", stdin);
    	freopen("QAQ_bipartite_two.out", "w", stdout);
    	n = read();
    	len = 1; while(len <= n) len <<= 1;
    	inv[1] = fac[0] = facInv[0] = 1;
    	for(int i=1; i<=n; i++) {
    		if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P;
    		fac[i] = fac[i-1] * i %P;
    		facInv[i] = facInv[i-1] * inv[i] %P;
    	}
    
    	for(int i=0; i<=n; i++) a[i] = facInv[i] * Pow(Pow(qr2, (ll) i * i %(P-1) ), P-2) %P;
    	fft::sqr(a, len<<1);
    	for(int i=0; i<=n; i++) a[i] = a[i] * Pow(qr2, (ll) i * i %(P-1)) %P;
    	fft::sqrt(a, f, len);
    	printf("%lld
    ", (ll) f[n] * fac[n] %P);
    }
    
    

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N = (1<<18) + 5, P = 998244353, qr2 = 116195171, inv2 = (P+1)/2;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    ll Pow(ll a, int b) {
    	ll ans = 1;
    	for(; b; b >>= 1, a = a * a %P)
    		if(b & 1) ans = ans * a %P;
    	return ans;
    }
    
    ll inv[N], fac[N], facInv[N];
    namespace fft {
    	int rev[N];
    	void dft(int *a, int n, int flag) { 
    		int k = 0; while((1<<k) < n) k++;
    		for(int i=0; i<n; i++) {
    			rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
    			if(i < rev[i]) swap(a[i], a[rev[i]]);
    		}
    		for(int l=2; l<=n; l<<=1) {
    			int m = l>>1;
    			ll wn = Pow(3, flag == 1 ? (P-1)/l : P-1-(P-1)/l);
    			for(int *p = a; p != a+n; p += l) 
    				for(int k=0, w=1; k<m; k++, w = w*wn%P) {
    					int t = (ll) w * p[k+m] %P;
    					p[k+m] = (p[k] - t + P) %P;
    					p[k] = (p[k] + t) %P;
    				}
    		}
    		if(flag == -1) {
    			ll inv = Pow(n, P-2);
    			for(int i=0; i<n; i++) a[i] = a[i] * inv %P;
    		}
    	}
    
    	void sqr(int *a, int n) {
    		dft(a, n, 1);
    		for(int i=0; i<n; i++) a[i] = (ll) a[i] * a[i] %P;
    		dft(a, n, -1);
    	}
    
    	void inverse(int *a, int *b, int l) {
    		static int t[N];
    		if(l == 1) {b[0] = Pow(a[0], P-2); return;}
    		inverse(a, b, l>>1);
    		int n = l<<1;
    		for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0; 
    		dft(t, n, 1); dft(b, n, 1);
    		for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P;
    		dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
    	}
    
        void ln(int *a, int *b, int l) {
            static int da[N], ia[N];
            int n = l<<1;
            for(int i=0; i<n; i++) da[i] = ia[i] = 0;
            for(int i=0; i<l-1; i++) da[i] = (ll) (i+1) * a[i+1] %P;
            inverse(a, ia, l);
            dft(da, n, 1); dft(ia, n, 1);
            for(int i=0; i<n; i++) b[i] = (ll) da[i] * ia[i] %P;
            dft(b, n, -1);
            for(int i=l-1; i>0; i--) b[i] = (ll) inv[i] * b[i-1] %P; b[0] = 0;
            for(int i=l; i<n; i++) b[i] = 0;
        }
    }
    
    int n, a[N], f[N], len;
    int main() {
    	//freopen("in", "r", stdin);
    	freopen("QAQ_bipartite_thr.in", "r", stdin);
    	freopen("QAQ_bipartite_thr.out", "w", stdout);
    	n = read();
    	len = 1; while(len <= n) len <<= 1;
    	inv[1] = fac[0] = facInv[0] = 1;
    	for(int i=1; i<=len; i++) {
    		if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P;
    		fac[i] = fac[i-1] * i %P;
    		facInv[i] = facInv[i-1] * inv[i] %P;
    	}
    
    	for(int i=0; i<=n; i++) a[i] = facInv[i] * Pow(Pow(qr2, (ll) i * i %(P-1) ), P-2) %P;
    	fft::sqr(a, len<<1);
    	for(int i=0; i<=n; i++) a[i] = a[i] * Pow(qr2, (ll) i * i %(P-1)) %P;
    	fft::ln(a, f, len);
    	printf("%lld
    ", f[n] * fac[n] %P * inv2 %P);
    }
    
    
  • 相关阅读:
    vue 5 父子组件及组件间数据传递 学习代码片段
    微信小程序设置数组对象的值
    微信小程序样式拼接 类名三元运算 以及条件拼接
    超简易 消息通知滚动 pc移动适用
    js 批量监听-序号的闭包问题
    docker基础
    mysql
    mongodb
    django-restframework_认证
    SSM 整合
  • 原文地址:https://www.cnblogs.com/candy99/p/6803766.html
Copyright © 2011-2022 走看看