zoukankan      html  css  js  c++  java
  • 生成函数

    这可能是最让我摸不着头脑的知识点了......

    《组合数学》第7章有很多好玩的例子。

    反正说着也不清楚,还是刷题好了.....

    CF438E 小朋友和二叉树参考资料

    定义一个二叉树的权值为所有点权之和,每个点的点权只能在一个集合c中选择。问权值为1~m的树共有多少种。

    设G(x)为数组c的生成函数,F(x)为我们的答案的生成函数,那么考虑它自己的关系,我们有:

    F(x) = G(x)F2(x) + 1

    这个毒瘤是怎么来的...G(x)是根的点权,F2(x)是两个儿子。 + 1是它作为子树可能为空树,此时有一个方案,就是常数项为1。

    虽然这样说但还是不太明白.....

    把上面那个方程解了,用求根公式可以得到一个东西,但是是不能直接算的,因为G(x)是分母,而常数项为0不能求逆。

    于是分子有理化即可。需要多项式开根 + 多项式求逆.....

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <cmath>
      5 
      6 typedef long long LL;
      7 const int N = 100010;
      8 const LL MO = 998244353, G = 3;
      9 typedef LL arr[N << 4];
     10 
     11 arr f, g, g2, A, B, inv_t, sqrt_t, r;
     12 LL inv2;
     13 
     14 inline LL qpow(LL a, LL b) {
     15     LL ans = 1;
     16     while(b) {
     17         if(b & 1) ans = ans * a % MO;
     18         a = a * a % MO;
     19         b = b >> 1;
     20     }
     21     return ans;
     22 }
     23 
     24 inline void prework(int n) {
     25     static int R = 0;
     26     if(R == n) return;
     27     R = n;
     28     int lm = 1;
     29     while((1 << lm) < n) lm++;
     30     for(int i = 0; i < n; i++) {
     31         r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
     32     }
     33     return;
     34 }
     35 
     36 inline void NTT(LL *a, int n, int f) {
     37     prework(n);
     38     for(int i = 0; i < n; i++) {
     39         if(i < r[i]) std::swap(a[i], a[r[i]]);
     40     }
     41     for(int len = 1; len < n; len <<= 1) {
     42         LL Wn = qpow(G, (MO - 1) / (len << 1));
     43         if(f == -1) Wn = qpow(Wn, MO - 2);
     44         for(int i = 0; i < n; i += (len << 1)) {
     45             LL w = 1;
     46             for(int j = 0; j < len; j++) {
     47                 LL t = a[i + len + j] * w % MO;
     48                 a[i + len + j] = (a[i + j] - t) % MO;
     49                 a[i + j] = (a[i + j] + t) % MO;
     50                 w = w * Wn % MO;
     51             }
     52         }
     53     }
     54     if(f == -1) {
     55         LL inv = qpow(n, MO - 2);
     56         for(int i = 0; i < n; i++) {
     57             a[i] = a[i] * inv % MO;
     58         }
     59     }
     60     return;
     61 }
     62 
     63 /*inline void mul(const LL *a, const LL *b, LL *c, int n) {
     64     int len = 1;
     65     while(len < n) len <<= 1;
     66     memcpy(A, a, n * sizeof(LL)); memset(A + n, 0, (len - n) * sizeof(LL));
     67     memcpy(B, b, n * sizeof(LL)); memset(B + n, 0, (len - n) * sizeof(LL));
     68     NTT(A, len, 1); NTT(B, len, 1);
     69     for(int i = 0; i < len; i++) c[i] = A[i] * B[i] % MO;
     70     NTT(c, len, -1);
     71     memset(c + n, 0, (len - n) * sizeof(LL));
     72     return;
     73 }*/
     74 
     75 void Inv(const LL *a, LL *b, int n) {
     76     if(n == 1) {
     77         b[0] = qpow(a[0], MO - 2);
     78         b[1] = 0;
     79         return;
     80     }
     81     Inv(a, b, n >> 1);
     82     /// ans = b * (2 - a * b)
     83     memcpy(A, a, n * sizeof(LL)); memset(A + n, 0, n * sizeof(LL));
     84     memcpy(B, b, n * sizeof(LL)); memset(B + n, 0, n * sizeof(LL));
     85     NTT(A, n << 1, 1); NTT(B, n << 1, 1);
     86     for(int i = 0; i < (n << 1); i++) b[i] = B[i] * (2 - A[i] * B[i] % MO) % MO;
     87     NTT(b, n << 1, -1);
     88     memset(b + n, 0, n * sizeof(LL));
     89     return;
     90 }
     91 
     92 inline void getInv(const LL *a, LL *b, int n) {
     93     int len = 1;
     94     while(len < n) len <<= 1;
     95     memcpy(inv_t, a, n * sizeof(LL)); memset(inv_t + n, 0, (len - n) * sizeof(LL));
     96     Inv(inv_t, b, len);
     97     memset(b + n, 0, (len - n) * sizeof(LL));
     98     return;
     99 }
    100 
    101 void Sqrt(const LL *a, LL *b, int n) {
    102     if(n == 1) {
    103         b[0] = sqrt(a[0]);
    104         b[1] = 0;
    105         return;
    106     }
    107     Sqrt(a, b, n >> 1);
    108     /// ans = (b + a / b) / 2
    109     Inv(b, B, n);
    110     memcpy(A, a, n * sizeof(LL)); memset(A + n, 0, n * sizeof(LL));
    111     NTT(A, n << 1, 1); NTT(B, n << 1, 1);
    112     for(int i = 0; i < (n << 1); i++) B[i] = A[i] * B[i] % MO;
    113     NTT(B, n << 1, -1);
    114     for(int i = 0; i < n; i++) b[i] = (b[i] + B[i]) * inv2 % MO;
    115     memset(b + n, 0, n * sizeof(LL));
    116     return;
    117 }
    118 
    119 inline void getSqrt(const LL *a, LL *b, int n) {
    120     int len = 1;
    121     while(len < n) len <<= 1;
    122     memcpy(sqrt_t, a, n * sizeof(LL)); memset(sqrt_t + n, 0, (len - n) * sizeof(LL));
    123     Sqrt(sqrt_t, b, len);
    124     memset(b + n, 0, (len - n) * sizeof(LL));
    125     return;
    126 }
    127 
    128 /*inline void check() {
    129     int n;
    130     scanf("%d", &n);
    131     for(int i = 0; i < n; i++) scanf("%lld", &f[i]);
    132     getSqrt(f, g, n);
    133     for(int i = 0; i < n; i++) {
    134         printf("%lld ", (g[i] + MO) % MO);
    135     }
    136     return;
    137 }*/
    138 
    139 int main() {
    140     inv2 = (MO + 1) / 2;
    141 
    142     int n, m;
    143     scanf("%d%d", &n, &m);
    144     m++;
    145     for(int i = 1, x; i <= n; i++) {
    146         scanf("%d", &x);
    147         g[x] = -4;
    148     }
    149     g[0] = 1; /// 1 - 4G
    150     getSqrt(g, g2, m);
    151     g2[0]++;
    152     getInv(g2, g, m);
    153 
    154     for(int i = 1; i < m; i++) {
    155         printf("%lld
    ", (2 * g[i] % MO + MO) % MO);
    156     }
    157     return 0;
    158 }
    AC代码

    关于指数生成函数(EGF):若fi为得出一个大小为i的有标号集合的方案数,相应的EGF为F(x)

    gi为得出一个由若干个集合组成的大小为i的有标号大集合的方案数,G(x)为其相应的EGF。

    那么有eF(x) = G(x),ln(G(x)) = F(x)。

    你要问我为什么?背诵吧,不为什么。两个简单的例子是森林和树,图和连通图。

    而且这个东西在带权的时候同样适用。具体的说,如果fi是选出一个大小为i的集合的所有方案权值之和

    gi为所有大集合的权值之和。且定义大集合的权值为小集合的权值之积,那么式子仍然适用。上面的是权值全为1的特殊情况。

  • 相关阅读:
    (转)Unity3D 开发优秀技术资源汇总
    (转)Unity3d通过Action注册事件,回调方法
    (转)Unity3D研究院之游戏架构脚本该如何来写(三十九)
    (转)Unity3D研究院之异步加载游戏场景与异步加载游戏资源进度条(三十一)
    Unity3D的主要类图
    C# 事件和Unity3D
    unity3d 场景配置文件生成代码
    497. Random Point in Non-overlapping Rectangles
    478. Generate Random Point in a Circle
    470. Implement Rand10() Using Rand7() (拒绝采样Reject Sampling)
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10462671.html
Copyright © 2011-2022 走看看