• BZOJ3684 大朋友与多叉树(拉格朗日反演)


    BZOJ3684 大朋友与多叉树(拉格朗日反演)

    题目大意

    我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为1的结点是叶子结点;对于任一点权大于1的结点u,u的孩子数目deg[u]属于集合D,且u的点权等于这些孩子结点的点权之和。
    给出一个整数s,你能求出根节点权值为s的神犇多叉树的个数吗?请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。
    我们只需要知道答案关于950009857(453*2^21+1,一个质数)取模后的值。

    数据范围

    1<=m<s<=10^5, 2<=d[i]<=s

    解题思路

    拉格朗日反演经典题

    写出递推式

    [T(x) = x+sum_{iin S}T(x)^i ]

    使用拉格朗日反演

    [x = T(x)-sum_{i in S}T(x)^i ]

    (G(x)=T(x))(F(x)=x-sum_{iin S}x^i)

    (F(G(X)) = x),所以可以直接求出 ([x^n]G(x)=frac 1n[x^{n-1}]{left(frac{x}{F(x)} ight)}^n)

    代码

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x, char ed = '
    ')
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar(ed);
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int N = 333400;
    const int P = 950009857;
    int r[N], lim, n;
    ll A[N], B[N], C[N], D[N], E[N], f[N], g[N];
    ll inv[N];
    
    void init(void) {
    	inv[0] = inv[1] = 1;
    	for (int i = 2;i <= 2 * n; i++)
    		inv[i] = inv[P % i] * (P - P / i) % P;
    }
    
    ll fpw(ll x, ll mi) {
    	ll res = 1;
    	for (; mi; mi >>= 1, x = x * x % P)
    		if (mi & 1) res = res * x % P;
    	return res;
    }
    
    void NTT(ll *a, int ty) {
    	for (int i = 0;i < lim; i++)
    		if (r[i] > i) swap(a[i], a[r[i]]);
    	for (int i = 1;i < lim; i <<= 1) {
    		ll wn = fpw(7, (P - 1) / (i << 1));
    		for (int j = 0;j < lim; j += (i << 1)) {
    			ll w = 1;
    			for (int k = 0;k < i; k++, w = w * wn % P) {
    				ll x = a[j+k], y = a[i+j+k] * w % P;
    				a[j+k] = (x + y) % P, a[i+j+k] = (x - y + P) % P;
    			}
    		}
    	}
    	if (ty == -1) {
    		ll inv = fpw(lim, P - 2);
    		for (int i = 0;i < lim; i++)
    			a[i] = a[i] * inv % P;
    		reverse(a + 1, a + lim);
    	}
    }
    
    
    /*
    
    F(G) - A = 0;
    F(G0) - A = 0;
    0 = T(G0)+T(G0)'(G-G0)
    G = G0-T(G0)/T(G0)'
    
    1/G0 - A = 0;
    
    G = G0 + (1/G0-A)G0^2
    G = G0 + G0 - G0^2A
    G = G0(2 - A*G0)
    
    */
    
    void Inv(ll *a, ll *b, int deg) {
    	b[0] = fpw(a[0], P - 2); int len;
    	for (len = 2;len < (deg << 1); len <<= 1) {
    		lim = len << 1;
    		for (int i = 1;i < lim; i++)
    			r[i] = (r[i>>1]>>1) | ((i & 1) ? len : 0);
    		for (int i = 0;i < len; i++) A[i] = a[i], B[i] = b[i];
    		NTT(A, 1), NTT(B, 1);
    		for (int i = 0;i < lim; i++)
    			b[i] = (2 + (P - A[i]) * B[i]) % P * B[i] % P;
    		NTT(b, -1);
    		for (int i = len;i < lim; i++) b[i] = 0;
    	}
        for (int i = 0;i < len; i++) A[i] = B[i] = 0;
    }
    
    void chick(ll *a, int deg) {
    	for (int i = deg - 1;i >= 1; i--)
    		a[i] = a[i-1] * inv[i] % P;
    	a[0] = 0;
    }
    
    void door(ll *a, int deg) {
    	for (int i = 1;i < deg; i++)
    		a[i-1] = a[i] * i % P;
    	a[deg - 1] = 0;
    }
    
    void Ln(ll *a, int deg) {
    	Inv(a, C, deg), door(a, deg);
    	NTT(a, 1), NTT(C, 1);
    	for (int i = 0;i < lim; i++)
    		a[i] = a[i] * C[i] % P;
    	NTT(a, -1), chick(a, deg);
    }
    
    /*
    
    F(G) - A = 0;
    F(G0) - A = 0;
    0 = T(G0)+T(G0)'(G-G0)
    G = G0-T(G0)/T(G0)'
    
    1/G0 - A = 0;
    
    G = G0 + (LnG0-A)G0
    G = -(-1+LnG0-A)G0
    
    */
    
    void Exp(ll *a, ll *b, int deg) {
    	b[0] = 1; int len;
    	for (len = 2;len < (deg << 1); len <<= 1) {
    		lim = len << 1;
    		for (int i = 0;i < len; i++) D[i] = b[i];
    		Ln(D, len); D[0] = (a[0] + 1 - D[0] + P) % P;
    		for (int i = 1;i < len; i++)
    			D[i] = (a[i] - D[i] + P) % P;
    		NTT(D, 1), NTT(b, 1);
    		for (int i = 0;i < lim; i++)
    			b[i] = b[i] * D[i] % P;
    		NTT(b, -1);
    		for (int i = len;i < lim; i++) b[i] = 0;
    	}
    }
    
    ll G[N];
    void lage() {
    	Inv(f, E, n), Ln(E, n);
    	for (int i = 0;i < n; i++) 
    		E[i] = E[i] * n % P;
    	Exp(E, G, n);
    }
    
    int m;
    int main() {
    	read(n), read(m), init(); f[0] = 1;
    	for (int i = 0, t;i < m; i++) read(t), f[t-1] += P - 1;
    	lage();
    	write(G[n-1] * inv[n] % P);
    	return 0;
    }
    
  • 相关阅读:
    面试常问题
    雷达无线电系列(五)拟合优度检验(matlab)
    LDAP轻量级目录访问协议总结(待完成)
    zipkin数据追踪(待完成)
    git多定制版本管理
    git单修改推送多分支(cherry-pick)
    git工作流及插件使用说明
    基金-股票-期权知识总结(待完成)
    java AESRSA加密解密样例
    分享一个统计文档中不同key的个数的python脚本
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13397192.html
Copyright © 2020-2023  润新知