zoukankan      html  css  js  c++  java
  • Re.常系数齐次递推

    前言

    嗯   我之前的不知道多少天看这个的时候到底在干什么呢

    为什么那么。。  可能大佬们太强的缘故

    最后仔细想想思路那么的emmm 

    不说了  要落泪了 

    唔唔唔


     前置

    多项式求逆

    多项式除法/取模


    常系数齐次递推目的

    求一个满足k阶齐次线性递推数列ai的第n

    即: 

    给出f1--fk,a0--ak-1求an

    N=1e9,K=32000


     常系数齐次递推主要思路

    emmm矩阵快速幂怎么样都应该会的

    设转移矩阵为A,st=[a0,a1...ak-2,ak-1]为初始矩阵

    显然an=(st*An)0

    O(k3logn)和O(k2logklogn)的矩阵快速幂在此范围下显然太暴力了

    发现k过大时时间复杂度主要花在矩阵乘法上

    考虑如何不用矩阵通过多项式来计算答案

    先考虑把An转化为A0--Ak-1组合出来的和

    设An=Q(A)*G(A)+R(A)

    Q,G,R是以矩阵为x(参数)的多项式

    当强制G的多项式的最高次数为k次方

    那么可写成An=Q(A)*G(A)+ciAi

    此时如果再强制试使得G(A)为0时

    那么Q(A)*G(A)=0

    An=ciAi=R(A)

    所以ciAi=An%G(A)

    通过多项式取模就可将An转化为ciAi

    通过上面的推导发现an=(st*An)0=(st*ciAi)0=(ciAist)0

    因为我们每次只取矩阵的第0项  每转移一次下一项就往上移一个位置 原来的第0项就去掉

    所以Aist就等于sti

    最后的an=cisti

    这样只要找出之前要求的那个G(A)就可以O(k)得出答案了

    那么如何求出G(A)

    设G(A)=giAi=0

    这里有个我暂时不会的结论

    如果递推系数为f1--fn

    那么gk-i=fi,gk=1

    所以最后流程就是

    1.求出G(A)

    2.用快速幂和多项式取模求出An在模G(A)时的余数R(A) 也就是把An转化为A1--Ak的组合

    3.计算答案an=cisti


    代码

    这 时隔多年我中于调出来了一份常数巨大的代码 

     #include<bits/stdc++.h> 
    using namespace std;
    #define ll long long
    #define C getchar()-48
    inline ll read()
    {
        ll s=0,r=1;
        char c=C;
        for(;c<0||c>9;c=C) if(c==-3) r=-1;
        for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
        return s*r;
    } 
    const int p=998244353,G=3,N=140010;
    int n,k,mx,cs,qvq,tz;
    ll rev[N];
    ll f[N],st[N],g[N],invg[N];
    ll tmp[N],tmp1[N],tmp2[N],tmpa[N],tmpb[N];
    ll a[N],ans[N];
    inline ll ksm(ll a,ll b)
    {
        ll ans=1;
        while(b)
        {
            if(b&1) ans=(ans*a)%p;
            a=(a*a)%p;
            b>>=1;
        }
        return ans;
    } 
    inline void ntt(ll *a,ll n,ll kd)
    {
        for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
        for(int i=1;i<n;i<<=1)
        {
            ll gn=ksm(G,(p-1)/(i<<1));
            for(int j=0;j<n;j+=(i<<1))
            {
                ll t1,t2,g=1;
                for(int k=0;k<i;k++,g=g*gn%p)
                {
                    t1=a[j+k],t2=g*a[j+k+i]%p;
                    a[j+k]=(t1+t2)%p,a[j+k+i]=(t1-t2+p)%p;
                } 
            }
        }
        if(kd==1) return;
        ll ny=ksm(n,p-2);
        reverse(a+1,a+n);
        for(int i=0;i<n;i++) a[i]=a[i]*ny%p;
    } 
    inline void cl(ll *a,ll *b,ll n,ll m,ll len,ll w)
    {
        for(int i=0;i<len;i++) tmp1[i]=i<n?a[i]:0;
        for(int i=0;i<len;i++) tmp2[i]=i<m?b[i]:0;
        for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(w-1));
    }
    inline void polyinv(ll *a,ll *b,ll ed)
    {
        b[0]=ksm(a[0],p-2);
        for(int k=1,j=0;k<=(ed<<1);k<<=1,j++)
        {
            ll len=k<<1;
            cl(a,b,k,k,len,j+1);
            ntt(tmp1,len,1);ntt(tmp2,len,1);
            for(int i=0;i<len;i++) b[i]=tmp2[i]*(2ll-tmp1[i]*tmp2[i]%p+p)%p;
            ntt(b,len,-1);
            for(int i=k;i<len;i++) b[i]=0;
        }
    }
    inline void polymul(ll *a,ll *b,ll *c,ll n,ll m)
    {
        ll len=1,w=0;
        while(len<=(n+m)) len<<=1,w++;
        cl(a,b,n,m,len,w);
        ntt(tmp1,len,1);ntt(tmp2,len,1);
        for(int i=0;i<len;i++) c[i]=tmp1[i]*tmp2[i]%p;
        ntt(c,len,-1);
    }
    inline void polymod(ll *a,ll n=mx<<1,ll m=k)
    {                   
        int ed=(mx<<1);while(a[--ed]==0);if(ed<k) return; 
        
        n=ed;
        reverse(a,a+1+n);
        polymul(a,invg,tmpa,n+1,n-m+1);    
        reverse(tmpa,tmpa+n-m+1);
        reverse(a,a+1+n);
        
        polymul(g,tmpa,tmpb,m+1,n-m+1);
        for(int i=0;i<k;i++) a[i]=(a[i]-tmpb[i]+p)%p;
        for(int i=k;i<=ed;i++)a[i]=0;
        for(int i=0;i<(mx<<1);i++) tmpa[i]=tmpb[i]=0;
    }
    int main()
    {
        n=read(),k=read();mx=1,cs=0;
        while(mx<=k) mx<<=1,cs++;
        for(int i=1;i<=k;i++) f[i]=read(),f[i]=f[i]<0?f[i]+p:f[i];
        for(int i=0;i<k;i++) st[i]=read(),st[i]=st[i]<0?st[i]+p:st[i];
        for(int i=1;i<=k;i++) g[k-i]=p-f[i];g[k]=1;
        for(int i=0;i<=k;i++) tmp[i]=g[i];
        
        reverse(tmp,tmp+1+k);
        polyinv(tmp,invg,mx);
        for(int i=mx;i<=(mx<<1);i++) invg[i]=0;
        for(int i=0;i<=k;i++) tmp[i]=0;
        for(int i=0;i<(mx<<1);i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(cs+1-1));
        ans[0]=1;a[1]=1;
        while(n)
        {
            if(n&1){polymul(ans,a,ans,k,k); polymod(ans);}
            polymul(a,a,a,k,k); polymod(a);
            n>>=1;
        }
        for(int i=0;i<k;i++) qvq=(qvq+ans[i]*st[i])%p;
        cout<<qvq; 
        return 0;
    }
  • 相关阅读:
    假期学习总结3
    内部表操作
    Hive基础操作
    Hive数据仓库基本概念
    假期学习总结2
    MapReduce基础介绍
    HDFS的高可用机制和联邦机制
    tensorflow学习笔记2
    tensorflow学习笔记1
    python使用tensorflow训练数据集时报错
  • 原文地址:https://www.cnblogs.com/1436177712qqcom/p/10497930.html
Copyright © 2011-2022 走看看