zoukankan      html  css  js  c++  java
  • [luogu5162]WD与积木

    设$g_{n}$表示$n$个积木放的方案数,枚举最后一层所放的积木,则有$g_{n}=sum_{i=1}^{n}c(n,i)g_{n-i}$(因为积木有编号的所以要选出$i$个)

    将组合数展开并化简,得到$frac{g_{n}}{n!}=sum_{i=1}^{n}frac{g_{n-i}}{i!(n-i)!}$,明显是一个分治fft的形式,转换为多项式求逆:

    令$g_{n}$的指数生成函数为$G(x)=sum_{i=0}^{infty}frac{g_{i}}{i!}x^{i}$,再令$H(x)=sum_{i=0}^{infty}frac{x^{i}}{i!}$,考虑$H(x)G(x)$,代入并将$i=0$和$j=0$提出可得$H(x)G(x)=sum_{i=0}^{infty}(sum_{j=0}^{i}H(x)[j]cdot G(x)[i-j])x^{i}=2G(x)-1$,即$G(x)=frac{1}{2-H(x)}$

    设$f_{n}$表示$n$个积木放的方案数的层数之和,那么根据期望的定义,答案$E=frac{f_{n}}{g_{n}}$

    类似的,可以写出$f_{n}$的递推式,即$f_{n}=g_{n}+sum_{i=1}^{n}c(n,i)f_{n-i}$($g_{n}$是因为每一个方案都要+1),将$g_{n}$的表达式展开,有$frac{f_{n}}{n!}=sum_{i=1}^{n}frac{f_{n-i}+g_{n-i}}{i!(n-i)!}$,同样去转换为多项式求逆:

    令$f_{n}$的指数生成函数为$F(x)=sum_{i=0}^{infty}frac{f_{i}}{i!}x^{i}$,$H(x)$和$G(x)$相同,考虑$H(x)(G(x)+F(x))$,类似上面可得$H(x)(G(x)+F(x))=G(x)+2F(x)$(注意$f_{0}=0$),即$F(x)=frac{(H(x)-1)G(x)}{2-H(x)}=(H(x)-1)G(x)^{2}$

    最终答案即$frac{F(x)[n]}{G(x)[n]}$(都除以了$n!$),注意最后一步不能将$frac{F(x)}{G(x)}$作为结果,因为这不等于答案

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N (1<<18)
     4 #define mod 998244353
     5 int t,n,a[N],c[N],h[N],g[N],f[N];
     6 int ksm(int n,int m){
     7     if (!m)return 1;
     8     int s=ksm(n,m>>1);
     9     s=1LL*s*s%mod;
    10     if (m&1)s=1LL*s*n%mod;
    11     return s;
    12 }
    13 void ntt(int *a,int n,int p){
    14     for(int i=0;i<(1<<n);i++){
    15         int rev=0;
    16         for(int j=0;j<n;j++)rev=rev*2+((i&(1<<j))>0);
    17         if (i<rev)swap(a[i],a[rev]);
    18     }
    19     for(int i=2;i<=(1<<n);i*=2){
    20         int s=ksm(3,(mod-1)/i);
    21         if (p)s=ksm(s,mod-2);
    22         for(int j=0;j<(1<<n);j+=i)
    23             for(int k=0,ss=1;k<(i>>1);k++,ss=1LL*ss*s%mod){
    24                 int x=a[j+k],y=1LL*a[j+k+(i>>1)]*ss%mod;
    25                 a[j+k]=(x+y)%mod;
    26                 a[j+k+(i>>1)]=(x+mod-y)%mod;
    27             }
    28     }
    29     if (p){
    30         int s=ksm((1<<n),mod-2);
    31         for(int i=0;i<(1<<n);i++)a[i]=1LL*a[i]*s%mod;
    32     }
    33 }
    34 void Inv(int *a,int *b,int n){
    35     if (!n){
    36         b[0]=ksm(a[0],mod-2);
    37         return;
    38     }
    39     Inv(a,b,n-1);
    40     for(int i=0;i<(1<<n);i++)c[i]=a[i];
    41     for(int i=(1<<n);i<(1<<n+1);i++)c[i]=0;
    42     ntt(c,n+1,0);
    43     ntt(b,n+1,0);
    44     for(int i=0;i<(1<<n+1);i++)b[i]=1LL*b[i]*(mod+2-1LL*c[i]*b[i]%mod)%mod;
    45     ntt(b,n+1,1);
    46     for(int i=(1<<n);i<(1<<n+1);i++)b[i]=0;
    47 }
    48 int main(){
    49     a[0]=1;
    50     for(int i=1;i<N;i++)a[i]=1LL*a[i-1]*ksm(i,mod-2)%mod;
    51     h[0]=(mod+2-a[0])%mod;
    52     for(int i=1;i<N/2;i++)h[i]=(mod-a[i])%mod;
    53     Inv(h,g,17);
    54     memcpy(f,g,sizeof(g));
    55     ntt(f,18,0);
    56     for(int i=0;i<N;i++)f[i]=1LL*f[i]*f[i]%mod;
    57     ntt(f,18,1);
    58     for(int i=N/2;i<N;i++)f[i]=0;
    59     ntt(f,18,0);
    60     h[0]=0;
    61     for(int i=1;i<N/2;i++)h[i]=a[i];
    62     ntt(h,18,0);
    63     for(int i=0;i<N;i++)f[i]=1LL*f[i]*h[i]%mod;
    64     ntt(f,18,1);
    65     scanf("%d",&t);
    66     while (t--){
    67         scanf("%d",&n);
    68         printf("%lld
    ",1LL*f[n]*ksm(g[n],mod-2)%mod);
    69     }
    70 }
    View Code
  • 相关阅读:
    程序员常用资源工具集合(建议收藏)
    程序员常用资源工具集合(建议收藏)
    16个烧光你脑细胞的悖论
    2.2_模型的选择
    2.1_Scikit-learn数据集
    Sklearn数据集与机器学习
    1.4_数据的特征选择
    1.4_特征的选择
    1.3_数据的特征预处理
    1.2_数据的特征抽取
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13859039.html
Copyright © 2011-2022 走看看