zoukankan      html  css  js  c++  java
  • BZOJ3456 城市规划 【多项式求逆】

    题目链接

    BZOJ3456

    题解

    之前我们用分治(ntt)(O(nlog^2n))的复杂度下做了这题,今天我们使用多项式求逆

    (f_n)表示(n)个点带标号无向连通图数
    (g_n)表示(n)个点图的数量,显然(g_n = 2^{{n choose 2}})

    枚举(1)号点所在联通块大小,我们有

    [g_n = sumlimits_{i = 1}^{n} {n - 1 choose i - 1}f_{i}g_{n - i} ]

    代入(g_n)

    [2^{{n choose 2}} = sumlimits_{i = 1}^{n} frac{(n - 1)!}{(n - i)!(i - 1)!}f_{i}2^{{n - i choose 2}} ]

    整理一下:

    [frac{2^{{n choose 2}}}{(n - 1)!} = sumlimits_{i = 1}^{n} frac{f_i}{(i - 1)!} * frac{2^{{n - i choose 2}}}{(n - i)!} ]

    发现是一个卷积的形式

    [F(x) = sumlimits_{n = 1}^{+infty} frac{f_n}{(n - 1)!} x^n ]

    [G(x) = sumlimits_{n = 0}^{+infty} frac{2^{{n choose 2}}}{n!} x^n ]

    [H(x) = sumlimits_{n = 1}^{+infty} frac{2^{{n choose 2}}}{(n - 1)!} x^n ]

    则有

    [H(x) = F(x)G(x) ]

    那么

    [F(x) = H(x)G^{-1}(x) ]

    多项式求逆后再求一次卷积就可求得答案

    复杂度(O(nlogn)),快了不少

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 300005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    const int G = 3,P = 1004535809;
    int f[maxn],g[maxn],h[maxn],gv[maxn],N;
    int fac[maxn],inv[maxn],fv[maxn];
    int c[maxn],R[maxn];
    inline int qpow(int a,LL b){
    	int re = 1;
    	for (; b; b >>= 1,a = 1ll * a * a % P)
    		if (b & 1) re = 1ll * re * a % P;
    	return re;
    }
    void NTT(int* a,int n,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 gn = qpow(G,(P - 1) / (i << 1));
    		for (int j = 0; j < n; j += (i << 1)){
    			int g = 1,x,y;
    			for (int k = 0; k < i; k++,g = 1ll * g * gn % P){
    				x = a[j + k]; y = 1ll * g * a[j + k + i] % P;
    				a[j + k] = (x + y) % P; a[j + k + i] = ((x - y) % P + P) % P;
    			}
    		}
    	}
    	if (f == 1) return;
    	int nv = qpow(n,P - 2); reverse(a + 1,a + n);
    	for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv % P;
    }
    void work(int deg,int* a,int* b){
    	if (deg == 1){b[0] = qpow(a[0],P - 2); return;}
    	work((deg + 1) >> 1,a,b);
    	int L = 0,n = 1;
    	while (n < (deg << 1)) n <<= 1,L++;
    	for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    	for (int i = 0; i < deg; i++) c[i] = a[i];
    	for (int i = deg; i < n; i++) c[i] = 0;
    	NTT(c,n,1); NTT(b,n,1);
    	for (int i = 0; i < n; i++)
    		b[i] = 1ll * ((2ll - 1ll * c[i] * b[i] % P) % P + P) % P * b[i] % P;
    	NTT(b,n,-1);
    	for (int i = deg; i < n; i++) b[i] = 0;
    }
    void init(){
    	fac[0] = fac[1] = inv[0] = inv[1] = fv[0] = fv[1] = 1;
    	for (int i = 2; i <= N; i++){
    		fac[i] = 1ll * fac[i - 1] * i % P;
    		inv[i] = 1ll * (P - P / i) * inv[P % i] % P;
    		fv[i] = 1ll * fv[i - 1] * inv[i] % P;
    	}
    	g[0] = 1;
    	for (int i = 1; i <= N; i++){
    		h[i] = 1ll * qpow(2,1ll * i * (i - 1) / 2) * fv[i - 1] % P;
    		g[i] = 1ll * qpow(2,1ll * i * (i - 1) / 2) * fv[i] % P;
    	}
    }
    int main(){
    	N = read();
    	init();
    	work(N + 1,g,gv);
    	int L = 0,n = 1;
    	while (n <= (N << 1)) n <<= 1,L++;
    	for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    	NTT(h,n,1); NTT(gv,n,1);
    	for (int i = 0; i < n; i++)
    		f[i] = 1ll * h[i] * gv[i] % P;
    	NTT(f,n,-1);
    	int ans = 1ll * f[N] * fac[N - 1] % P;
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    剑指 Offer——13. 调整数组顺序使奇数位于偶数前面
    剑指 Offer——3. 从尾到头打印链表
    剑指 Offer——2. 替换空格
    剑指 Offer——1. 二维数组中的查找
    LeetCode 905. Sort Array By Parity 按奇偶校验排列数组
    LeetCode 448. Find All Numbers Disappeared in an Array找到所有数组中消失的元素
    SSH 代码笔记
    anaconda3安装caffe
    opencv多版本安装
    人脸文章与数据库
  • 原文地址:https://www.cnblogs.com/Mychael/p/9046220.html
Copyright © 2011-2022 走看看