zoukankan      html  css  js  c++  java
  • 【BZOJ 4555】[Tjoi2016&Heoi2016]求和 多项式求逆/NTT+第二类斯特林数

    出处0.0
    用到第二类斯特林数的性质,做法好像很多,我打的是直接ntt,由第二类斯特林数的容斥公式可以推出,我们可以对于每一个i,来一次ntt求出他与所有j组成的第二类斯特林数的值,这个时候我们是O(n^2logn)的,还不如暴力,但是我们发现,对于刚刚提到的容斥的式子,将其化为卷积形式后,其一边的每一项对于每一个i都相同,另一边的每一项是对于所有的i形成一个n项的等比数列,这样我们可以把成等比数列的一边求和,用固定的一边去卷他们的和,这时候的答案的每一项就是所有的i的这一项的和,然后我们再O(n)乘上阶乘和2的次幂就可以了.
    (一开始代码打错了,还以为那个公式在S(i,j)不存在的时候是错的……后来手玩了一下才发现他是对的……)
    补充:
    又用多项式求逆打了一遍,比上面那个做法慢了一倍……
    这道题求逆的具体做法参见http://blog.csdn.net/lych_cys/article/details/51512278
    感觉好神奇啊,把多项式当成数来推式子……
    这个东西感觉有点像CDQ+ntt……

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=400010;
    const int P=998244353;
    typedef long long LL;
    inline int Pow(int x,int y){
      int ret=1;
      while(y){
        if(y&1)ret=(LL)ret*x%P;
        x=(LL)x*x%P,y>>=1;
      }return ret;
    }
    int A[N],B[N],rev[N],len;
    int ai[N],bi[N],ci[N];
    int jie[N],ni[N],inv[N],n;
    inline void ntt(int *C,int opt){
      register int i,j,k,w;int wn,temp;
      for(i=1;i<len;++i)if(i<rev[i])std::swap(C[i],C[rev[i]]);
      for(k=2;k<=len;k<<=1){
        wn=Pow(3,(P-1)/k);
        if(opt==-1)wn=Pow(wn,P-2);
        for(i=0;i<len;i+=k){
          w=1;
          for(j=0;j<(k>>1);++j,w=(LL)w*wn%P){
            temp=(LL)w*C[i+j+(k>>1)]%P;
            C[i+j+(k>>1)]=(C[i+j]-temp+P)%P;
            C[i+j]=(C[i+j]+temp)%P;
          }
        }
      }
    }
    inline void mul(int *a,int *b,int *c,int n){
      len=1;while(len<n)len<<=1;int i;
      for(i=1;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
      for(i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
      ntt(A,1),ntt(B,1);
      for(i=0;i<len;++i)A[i]=(LL)A[i]*B[i]%P;
      ntt(A,-1);
      int Inv=Pow(len,P-2);
      for(i=0;i<len;++i)c[i]=(LL)A[i]*Inv%P;
    }
    int main(){
      scanf("%d",&n);int i,ans=1,temp=1;
      jie[0]=ni[0]=1,inv[1]=1;
      for(i=2;i<=n;++i)inv[i]=((-(LL)(P/i)*inv[P%i])%P+P)%P;
      for(i=1;i<=n;++i)jie[i]=(LL)jie[i-1]*i%P,ni[i]=(LL)ni[i-1]*inv[i]%P;
      bi[0]=0,bi[1]=n,ai[0]=1,ai[1]=P-1;
      for(i=2;i<=n;++i)
        bi[i]=(LL)i*(Pow(i,n)-1+P)%P*ni[i]%P*inv[i-1]%P,ai[i]=(i&1)?(P-ni[i]):ni[i];
      mul(ai,bi,ci,n+n+2);
      for(i=1;i<=n;++i)
        temp=(((LL)temp)<<1LL)%P,ans=(ans+(LL)ci[i]*temp%P*jie[i])%P;
      printf("%d
    ",ans);
      return 0;
    }
    直接ntt
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long LL;
    const int N=100010;
    const int P=998244353;
    inline int Pow(int x,int y){
      int ret=1;
      while(y){
        if(y&1)ret=(LL)ret*x%P;
        x=(LL)x*x%P,y>>=1;
      }return ret;
    }
    int len,n,A[N<<2],rev[N<<2];
    int g[N<<2],f[N<<2],jie[N],ni[N];
    inline void ntt(int *C,int opt){
      register int i,j,k,w;int wn,temp;
      for(i=1;i<len;++i)if(rev[i]>i)std::swap(C[i],C[rev[i]]);
      for(k=2;k<=len;k<<=1){
        wn=Pow(3,(P-1)/k);
        if(opt==-1)wn=Pow(wn,P-2);
        for(i=0;i<len;i+=k){
          w=1;
          for(j=0;j<(k>>1);++j,w=(LL)w*wn%P){
            temp=(LL)w*C[i+j+(k>>1)]%P;
            C[i+j+(k>>1)]=(C[i+j]-temp+P)%P;
            C[i+j]=(C[i+j]+temp)%P;
          }
        }
      }
    }
    inline void Inv(int *a,int *b,int cd){
      if(cd==1){b[0]=Pow(a[0],P-2);return;}
      Inv(a,b,cd>>1);
      int i,inv;len=cd<<1;
      for(i=1;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
      memcpy(A,a,cd<<2),memset(A+cd,0,cd<<2);
      ntt(A,1),ntt(b,1);
      for(i=0;i<len;++i)b[i]=(2-(LL)A[i]*b[i]%P+P)*b[i]%P;
      ntt(b,-1),inv=Pow(len,P-2);
      for(i=0;i<cd;++i)b[i]=(LL)b[i]*inv%P;
      memset(b+cd,0,cd<<2);
    }
    int main(){
      scanf("%d",&n);int i,cd,ans=0;
      jie[0]=ni[0]=1;
      for(i=1;i<=n;++i)jie[i]=(LL)jie[i-1]*i%P;
      ni[n]=Pow(jie[n],P-2);
      for(i=n-1;i>0;--i)ni[i]=(LL)ni[i+1]*(i+1)%P;
      g[0]=1;
      for(i=1;i<=n;++i)g[i]=(-2*ni[i]+P+P)%P;
      cd=1;
      while(cd<=n)cd<<=1;
      Inv(g,f,cd);
      for(i=0;i<=n;++i)ans=(ans+(LL)f[i]*jie[i])%P;
      printf("%d
    ",ans);
      return 0;
    }
    多项式求逆
  • 相关阅读:
    以&quot;小刀会“的成败论当今创业成败
    COCOS2D 学习笔记
    password加密的算法
    bzoj1087【SCOI2005】互不侵犯King
    HDU--2222--Keywords Search--AC自己主动机
    【leetcode】Subsets II (middle) ☆
    【leetcode】Word Search (middle)
    【hadoop2.6.0】利用JAVA API 实现数据上传
    【leetcode】Palindrome Partitioning II(hard) ☆
    【hadoop2.6.0】利用Hadoop的 Java API
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8480847.html
Copyright © 2011-2022 走看看