zoukankan      html  css  js  c++  java
  • 洛谷P4721 【模板】分治 FFT(生成函数+多项式求逆)

    传送门

    我是用多项式求逆做的因为分治FFT看不懂……

    upd:分治FFT的看这里

    话说这个万恶的生成函数到底是什么东西……

    我们令$F(x)=sum_{i=0}^infty f_ix^i,G(x)=sum_{i=0}^infty g_ix^i$,且$g_0=0$

    这俩玩意儿似乎就是$f(x)$和$g(x)$的生成函数

    那么就有$$F(x)G(x)=sum_{i=0}^infty x^isum_{j+k=i}f_jg_k$$

    然后根据题目,有$$f_i=sum_{j=1}^if_{i-j}g_j$$

    然后因为$g_0=0$,所以

    $$f_i=sum_{j+k=i}f_jg_k$$

    又因为该式子只有在$i=0$时不成立,于是代入并手算一下$i=0$的时候,可得$$F(x)G(x)=sum_{i=0}^infty f_ix^i-f_0x^0$$

    又因为$f_0=x^0=1$,可得$$F(x)G(x)=F(x)-1$$

    然后我们只要求它的前$n$项就可以了,所以取模$$F(x)G(x)equiv F(x)-1pmod{x^n}$$

    然后移项$$F(x)equivfrac{1}{1-G(x)}pmod{x^n}$$

    $$F(x)equiv(1-G(x))^{-1}pmod{x^n}$$

    然后去隔壁把多项式求逆的板子抄来就好了

     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 C=-1,Z;
    23 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    24 inline void print(int x){
    25     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    26     while(z[++Z]=x%10+48,x/=10);
    27     while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    28 }
    29 const int N=400005,P=998244353,G=3;
    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,r[N],g[N],f[N],A[N],B[N],O[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 work(int *a,int *b,int len){
    63     if(len==1) return (void)(b[0]=ksm(a[0],P-2));
    64     work(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;i<(len<<1);++i)
    68     A[i]=mul(mul(A[i],B[i]),B[i]);
    69     NTT(A,-1,len<<1);
    70     for(int i=0;i<len;++i) b[i]=dec(1ll*b[i]*2%P,A[i]);
    71 }
    72 int main(){
    73 //    freopen("testdata.in","r",stdin);
    74     n=read();
    75     for(int i=1;i<n;++i) g[i]=read();
    76     int len;for(len=1;len<n;len<<=1);
    77     for(int i=1;i<n;++i) g[i]=P-g[i];g[0]=1;
    78     work(g,f,len);
    79     for(int i=0;i<n;++i) print(f[i]);
    80     Ot();
    81     return 0;
    82 }
  • 相关阅读:
    创建自定义 AJAX 客户端控件(msdn)
    使用jquery的blockui插件显示弹出层
    Sql Server高手必备
    Js获取当前日期时间及其它操作
    在VS2010中创建自定义的代码段
    存储过程分页
    完美辨析各种高度区别
    程序员必备的正则表达式
    Sql日期格式化
    C#调用Quartz实例代码
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9746865.html
Copyright © 2011-2022 走看看