• CF438E The Child and Binary Tree(生成函数+多项式开根+多项式求逆)


    传送门

    可以……这很多项式开根模板……而且也完全不知道大佬们怎么把这题的式子推出来的……

    首先,这题需要多项式开根和多项式求逆。多项式求逆看这里->这里,这里讲一讲多项式开根

    多项式开方:已知多项式$B$,求多项式$A$满足$A^2equiv Bpmod{x^n}$(和多项式求逆一样这里需要取模,否则$A$可能会有无数项)

    假设我们已经求出$A'^2equiv Bpmod{x^n}$,考虑如何计算出$A^2equiv Bpmod{x^{2n}}$

    首先肯定存在$A^2equiv Bpmod{x^n}$

    然后两式相减$$A'^2-A^2equiv 0pmod{x^n}$$

    $$(A'-A)(A'+A)equiv 0pmod{x^n}$$

    我们假设$A'-Aequiv 0pmod{x^n}$,然后两边平方$$A'^2-2A'A+A^2equiv 0pmod{x^{2n}}$$

    (关于平方之后模数变化的原因可以看我多项式求逆那篇文章,里面有写)

    又因为$A^2equiv Bpmod{x^{2n}}$,代入得$$A'^2-2A'A+Bequiv 0pmod{x^{2n}}$$

    $$Aequivfrac{A'^2+B}{2A'}pmod{x^{2n}}$$

    那么这个只要递归计算就可以了

    然后多项式开方就讲到这里

    下面说一下本题的做法

    首先,我也不知道怎么想到的构造出生成函数,$C=sum_{i=1}^{lim}s_ix^i$,其中$s_i$表示$i$是否在集合中出现过,然后再设一个$F_k$表示权值为$k$时的答案

    因为一棵二叉树可以由根节点,左右子树构成(左右子树可以是空的)

    那么存在如下关系$$F_k=sum_{i=0}^ks_isum_{j=0}^{k-i}F_jF_{k-i-j}$$

    然后我也不知道怎么看出来的发现这是一个卷积的形式,即$$F=1+C*F*F$$(这里$*$是多项式乘法)(这里$1$是加上去的常数项,因为有$F_0=1$,即空树)

    把它看做一个一元二次方程求解,得$$F=frac{1pm sqrt{1-4C}}{2C}=frac{2}{1pmsqrt{1-4C}}$$

    然后因为$F_0=1,C_0=0$,所以符号取正,即$$F=frac{2}{1+sqrt{1-4C}}$$

    那么把多项式开根和多项式求逆的板子带进去就好了

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #define swap(x,y) (x^=y,y^=x,x^=y)
     6 #define mul(x,y) (1ll*x*y%P)
     7 #define add(x,y) (x+y>=P?x+y-P:x+y)
     8 #define dec(x,y) (x-y<0?x-y+P:x-y)
     9 using namespace std;
    10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    11 char buf[1<<21],*p1=buf,*p2=buf;
    12 inline int read(){
    13     #define num ch-'0'
    14     char ch;bool flag=0;int res;
    15     while(!isdigit(ch=getc()))
    16     (ch=='-')&&(flag=true);
    17     for(res=num;isdigit(ch=getc());res=res*10+num);
    18     (flag)&&(res=-res);
    19     #undef num
    20     return res;
    21 }
    22 char sr[1<<21],z[20];int K=-1,Z;
    23 inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
    24 inline void print(int x){
    25     if(K>1<<20)Ot();if(x<0)sr[++K]=45,x=-x;
    26     while(z[++Z]=x%10+48,x/=10);
    27     while(sr[++K]=z[Z],--Z);sr[++K]='
    ';
    28 }
    29 const int N=500005,P=998244353,G=3,inv2=499122177;
    30 inline int ksm(int a,int b){
    31     int res=1;
    32     while(b){
    33         if(b&1) res=mul(res,a);
    34         a=mul(a,a),b>>=1;
    35     }
    36     return res;
    37 }
    38 int n,m,r[N],A[N],B[N],C[N],D[N],O[N],d[N],c[N];
    39 void NTT(int *A,int type,int len){
    40     int limit=1,l=0;
    41     while(limit<len) limit<<=1,++l;
    42     for(int i=0;i<limit;++i)
    43     r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    44     for(int i=0;i<limit;++i)
    45     if(i<r[i]) swap(A[i],A[r[i]]);
    46     for(int mid=1;mid<limit;mid<<=1){
    47         int R=mid<<1,Wn=ksm(G,(P-1)/R);O[0]=1;
    48         for(int j=1;j<mid;++j) O[j]=mul(O[j-1],Wn);
    49         for(int j=0;j<limit;j+=R){
    50             for(int k=0;k<mid;++k){
    51                 int x=A[j+k],y=mul(O[k],A[j+k+mid]);
    52                 A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
    53             }
    54         }
    55     }
    56     if(type==-1){
    57         reverse(A+1,A+limit);
    58         for(int i=0,inv=ksm(limit,P-2);i<limit;++i)
    59         A[i]=mul(A[i],inv);
    60     }
    61 }
    62 void Inv(int *a,int *b,int len){
    63     if(len==1) return (void)(b[0]=ksm(a[0],P-2));
    64     Inv(a,b,len>>1);
    65     for(int i=0;i<len;++i) A[i]=a[i],B[i]=b[i];
    66     NTT(A,1,len<<1),NTT(B,1,len<<1);
    67     for(int i=0,l=(len<<1);i<l;++i) A[i]=mul(mul(A[i],B[i]),B[i]);
    68     NTT(A,-1,len<<1);
    69     for(int i=0;i<len;++i) b[i]=dec(1ll*(b[i]<<1)%P,A[i]);
    70     for(int i=0,l=(len<<1);i<l;++i) A[i]=B[i]=0;
    71 }
    72 void Sqrt(int *a,int *b,int len){
    73     if(len==1) return (void)(b[0]=a[0]);
    74     Sqrt(a,b,len>>1);
    75     for(int i=0;i<len;++i) C[i]=a[i];
    76     Inv(b,D,len);
    77     NTT(C,1,len<<1),NTT(D,1,len<<1);
    78     for(int i=0,l=len<<1;i<l;++i) D[i]=mul(D[i],C[i]);
    79     NTT(D,-1,len<<1);
    80     for(int i=0;i<len;++i) b[i]=mul(add(b[i],D[i]),inv2);
    81     for(int i=0,l=(len<<1);i<l;++i) C[i]=D[i]=0;
    82 }
    83 int main(){
    84 //    freopen("testdata.in","r",stdin);
    85     n=read(),m=read();
    86     for(int i=1,x;i<=n;++i) x=read(),++d[x];
    87     int len;for(len=1;len<=m;len<<=1);
    88     for(int i=1;i<len;++i) d[i]=(-4*d[i]+P)%P;
    89     ++d[0];
    90     Sqrt(d,c,len);
    91     for(int i=0;i<len;++i) d[i]=0;
    92     c[0]=add(c[0],1);
    93     Inv(c,d,len);
    94     for(int i=0;i<=m;++i) d[i]=add(d[i],d[i]);
    95     for(int i=1;i<=m;++i) print(d[i]);
    96     Ot();
    97     return 0;
    98 }
  • 相关阅读:
    撩课-Python-每天5道面试题-第8天
    声明提前、原型、静态方法的一些所得
    梳理ajax
    两数之和、整数反转、回文数
    node 基础API(fs)
    node 基础API(event)
    node 基础API(Buffer)
    node 基础API(path)
    node 调试技巧
    node process(进程) 几个常用属性
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9747126.html
Copyright © 2020-2023  润新知