zoukankan      html  css  js  c++  java
  • 一个人的高三楼:多项式卷积,生成函数

    Description:

    一天的学习快要结束了,高三楼在晚自习的时候恢复了宁静。
    不过,HSD 桑还有一些作业没有完成,他需要在这个晚自习写完。比如这道数学题:

    1、给出一个数列,求它的前i项和$S_i$

    HSD 桑擅长数学,很快就把这题秒了……
    然而还有第二题:

    2、如果把上一问的前n项和看成一个新数列,请求出它的i项和

     

    看完第二题,还有第三题……HSD 桑已经预感到情况不妙了。
    HSD 桑大致看了看题,发现有些规律。其实就是在求

    次前缀和。如果我们借用函数迭代的标记,就是在求 $S_n^{(k)}$
    HSD 桑还有很多作业要写,请你帮助他完成这项作业。$mod 998244353$

    $n leq 100000 , k leq 2^{63}$

    时限:100ms

    废话:

    挺好的一道题。skyh一直在跟我说LNC给他颓了题解于是我也来做了。

    然而我并不会于是打表找规律直接发现$O(n log n)$的式子然后就完了。

    但是实际上丢了一个中间步骤$O(n log n log   k)$

    题解:

    设我们要求的$S_n^{(k)}$的生成函数$F_{(k)}(x)=sumlimits_{i=0}^{n-1} S_{i+1}^{(k)} x^i$

    然后考虑前缀和的过程,就是每一项都累加前面的所有项,也可以理解为每个数都为后面的项做贡献

    那么感觉好像已经有卷积形式了,让我们吧这个“贡献”方式也写成生成函数:

    $G(x)=sumlimits_{i=0}^{n-1}x^i$

    然后按照贡献规则我们能知道$F_{(k+1)}(x)=F_{(k)}(x) imes G(x)$

    生成函数就是多项式了,这很卷积,于是我们用快速幂的方式分别卷一下$F$和$G$就行。

    这样的复杂度是$O(n log n log   k)$的。时限故意卡掉了。

    考虑这个$G$函数的具体意义:在$F$函数的表上往下走一步的同时往右走了若干步

    根据范德蒙恒等式(我还是喜欢叫枣树定理),组合数可以合并成一个

    那么最后我们能知道它的答案就是$f[i]=sumlimits_{j=1}^{i} C_{k-1+i-j}^{k-1}  imes g[j]$

    其中$g$是原数组,$f$是答案数组。

    然后这是一个比较明显的卷积。至于怎么求组合数?

    线性递推一乘一除就好了,k太大要及时取模。

     1 #include<cstdio>
     2 #define mod 998244353
     3 #define int long long
     4 int n,C[300000],x[300000],k,bin=1,rev[300000],INV;
     5 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
     6 void NTT(int *a,int opt){
     7     for(int i=0;i<bin;++i)if(i<rev[i])a[i]^=a[rev[i]]^=a[i]^=a[rev[i]];
     8     for(int mid=1,wn;mid<bin;mid<<=1){
     9         wn=pow(3,(mod-1)/2/mid*opt+mod-1);
    10         for(int i=0;i<bin;i+=mid<<1)
    11             for(int j=0,w=1;j<mid;++j,w=w*wn%mod){
    12                 int x=a[i+j],y=a[i+j+mid]*w%mod;
    13                 a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
    14             }
    15     }
    16     if(opt==-1)for(int i=0;i<bin;++i)a[i]=a[i]*INV%mod;
    17 }
    18 main(){
    19     scanf("%lld%lld",&n,&k);k%=mod;
    20     while(bin<=n<<1)bin<<=1; INV=pow(bin,mod-2);
    21     for(int i=1;i<bin;++i)rev[i]=rev[i>>1]>>1|(i&1)*bin>>1;
    22     for(int i=0;i<n;++i)scanf("%lld",&x[i]);
    23     C[0]=1;
    24     for(int i=1;i<n;++i)C[i]=C[i-1]*(k+i-1)%mod*pow(i,mod-2)%mod;
    25     NTT(C,1);NTT(x,1);
    26     for(int i=0;i<bin;++i)x[i]=x[i]*C[i]%mod;
    27     NTT(x,-1);
    28     for(int i=0;i<n;++i)printf("%lld
    ",x[i]);
    29 }
    View Code
  • 相关阅读:
    JVM学习笔记(三)------内存管理和垃圾回收【转】
    JVM学习笔记(二)------Java代码编译和执行的整个过程【转】
    JVM学习笔记(一)------基本结构【转】
    Java程序编译和运行的过程【转】
    linux C判断文件是否存在【转】
    Java编译那些事儿【转】
    CTSC1999补丁VS错误题解
    ASP.NET MVC学前篇之Ninject的初步了解
    setSingleChoiceItems和setPositiveButton两者触发时期
    B. Sereja and Mirroring
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11760175.html
Copyright © 2011-2022 走看看