线性递推——BM模板

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define rep(i,a,n) for (ll i=a;i
#define per(i,a,n) for (ll i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((ll)(x).size())
typedef long long ll;
typedef vector<ll> VI;
typedef pair<ll, ll> PII;
const ll mod = 998244353;
ll powmod(ll a, ll b) {
    ll res = 1;
    a %= mod;
    assert(b >= 0);
    for (; b; b >>= 1) {
        if (b & 1)
            res = res*a%mod;
        a = a*a%mod;
    }
    return res;
}
namespace linear_seq {
const ll N = 10010;
ll res[N], base[N], _c[N], _md[N];
vector<ll> Md;
void mul(ll *a, ll *b, ll k) {
    rep(i, 0, k + k) _c[i] = 0;
    rep(i, 0, k) if (a[i])
        rep(j, 0, k) _c[i + j] = (_c[i + j] + a[i] * b[j]) % mod;
    for (ll i = k + k - 1; i >= k; i--)
        if (_c[i])
            rep(j, 0, SZ(Md)) _c[i - k + Md[j]] = (_c[i - k + Md[j]] - _c[i] * _md[Md[j]]) % mod;
    rep(i, 0, k) a[i] = _c[i];
}
ll solve(ll n,const VI &a,const VI &b) {
    ll ans = 0, pnt = 0;
    ll k = SZ(a);
    assert(SZ(a) == SZ(b));
    rep(i, 0, k) _md[k - 1 - i] = -a[i];
    _md[k] = 1;
    Md.clear();
    rep(i, 0, k) if (_md[i] != 0)
        Md.push_back(i);
    rep(i, 0, k) res[i] = base[i] = 0;
    res[0] = 1;
    while ((1ll << pnt) <= n)
        pnt++;
    for (ll p = pnt; p >= 0; p--) {
        mul(res, res, k);//主要复杂度:多项式乘法,如果追求速度换成NTT吧
        if ((n >> p) & 1) {
            for (ll i = k - 1; i >= 0; i--)
                res[i + 1] = res[i];
            res[0] = 0;
            rep(j, 0, SZ(Md)) res[Md[j]] = (res[Md[j]] - res[k] * _md[Md[j]]) % mod;
        }
    }
    rep(i, 0, k) ans = (ans + res[i] * b[i]) % mod;
    if (ans < 0)
        ans += mod;
    return ans;
}
void BM(VI &s,VI &C) {
    C.clear();
    C.pb(1);
    VI B(1, 1);
    ll L = 0, m = 1, b = 1;
    rep(n, 0, SZ(s)) {
        ll d = 0;
        rep(i, 0, L + 1) d = (d + (ll)C[i] * s[n - i]) % mod;
        if (d == 0)
            ++m;
        else if (2 * L <= n) {
            VI T = C;
            ll c = mod - d*powmod(b, mod - 2) % mod;
            while (SZ(C) < SZ(B) + m)
                C.pb(0);
            rep(i, 0, SZ(B)) C[i + m] = (C[i + m] + c*B[i]) % mod;
            L = n + 1 - L;
            B = T;
            b = d;
            m = 1;
        } else {
            ll c = mod - d*powmod(b, mod - 2) % mod;
            while (SZ(C) < SZ(B) + m)
                C.pb(0);
            rep(i, 0, SZ(B)) C[i + m] = (C[i + m] + c*B[i]) % mod;
            ++m;
        }
    }
}
ll gao(VI &a, ll n) {
    VI c;
    BM(a,c);
    c.erase(c.begin());
    rep(i, 0, SZ(c)) c[i] = (mod - c[i]) % mod;

    //递推式: c[0] x(n-1)+ c[1] x(n-2)+ c[2] x(n-3)...
    rep(i,0,SZ(c)){
        printf("%lld ",c[i]);
    }
    printf("\n");
    return solve(n, c, VI(a.begin(), a.begin() + SZ(c)));
}
};
int main() {
    // 前n项,输出第m项
    ll n,m;
    scanf("%lld%lld", &n,&m);m++;
    VI vec;
    for(int i=1;i<=n;i++){
        ll j;
        scanf("%lld",&j);
        vec.push_back(j);
    }
    printf("%lld\n", linear_seq::gao(vec, m - 1));
}

Another

#include 
#define rep(i,a,b) for(ll i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll N=25;
const ll mo=1e9+7;
//快速幂
ll fpow(ll a,ll b){
    ll ans=1;
    while(b>0){if(b&1)ans=ans*a%mo;b>>=1;a=a*a%mo;}
    return ans;
}
//BM算法 求线性递推数列的递推公式
vector<ll> BM(const vector<ll> &s){
    vector<ll> C={1},B={1},T;
    ll L=0,m=1,b=1;
    rep(n,0,s.size()-1){
        ll d=0;
        rep(i,0,L)d=(d+s[n-i]%mo*C[i])%mo;
        if(d==0)m++;
        else{
            T=C;
            ll t=mo-fpow(b,mo-2)*d%mo;
            while(C.size()<B.size()+m)C.push_back(0);
            rep(i,0,B.size()-1)C[i+m]=(C[i+m]+t*B[i])%mo;
            if(2*L>n)m++;
            else L=n+1-L,B=T,b=d,m=1;
        }
    }
    return C;
}
//矩阵快速幂求解数列单项值,s为初值,C为递推公式
ll MatrixSolve(const vector<ll> &s,const vector<ll> &C,ll n){
    if(n<s.size())return s[n];
    ll k=C.size()-1,b=n-k+1;
    static ll B[N][N],t[N],a[N],c[N][N];
    rep(i,0,k-1)a[i]=s[i];
    rep(i,0,k-1)rep(j,0,k-1)B[i][j]=j==0?((C[i+1]>0)*mo-C[i+1]):(i==j-1);
    while(b){
        if(b&1){
            rep(i,0,k-1)t[i]=0;
            rep(i,0,k-1)rep(j,0,k-1)t[i]=(t[i]+a[k-j-1]*B[j][k-i-1])%mo;
            rep(i,0,k-1)a[i]=t[i];
        }
        b>>=1;
        rep(i,0,k-1)rep(j,0,k-1)c[i][j]=0;
        rep(r,0,k-1)rep(j,0,k-1)if(B[r][j])rep(i,0,k-1)c[i][j]=(c[i][j]+B[i][r]*B[r][j])%mo;
        rep(i,0,k-1)rep(j,0,k-1)B[i][j]=c[i][j];
    }
    return a[k-1];
}
//更快的矩阵快速幂求解数列单项值,s为初值,C为递推公式
ll fastMatrixSolve(const vector<ll> &s,const vector<ll> &C,ll n){
    if(n<s.size())return s[n];
    ll k=C.size()-1,b=n-k+1;
    static ll B[N][N][64],t[N],a[N],c[N][N],init_flag=1;
    if(init_flag){
        init_flag=0;
        rep(i,0,k-1)rep(j,0,k-1)B[i][j][0]=j==0?((C[i+1]>0)*mo-C[i+1]):(i==j-1);
        for(ll it=1;it<64;it++){
            rep(i,0,k-1)rep(j,0,k-1)B[i][j][it]=0;
            rep(r,0,k-1)rep(j,0,k-1)if(B[r][j][it-1])rep(i,0,k-1)B[i][j][it]=(B[i][j][it]+B[i][r][it-1]*B[r][j][it-1])%mo;
        }
    }
    rep(i,0,k-1)a[i]=s[i];
    ll it=0;
    while(b){
        if(b&1){
            rep(i,0,k-1)t[i]=0;
            rep(i,0,k-1)rep(j,0,k-1)t[i]=(t[i]+a[k-j-1]*B[j][k-i-1][it])%mo;
            rep(i,0,k-1)a[i]=t[i];
        }
        b>>=1;
        it++;
    }
    return a[k-1];
}
//牛顿多项式插值
class NewtonPoly{
public:
    ll f[N],d[N],x[N],n=0;
    void add(ll X,ll Y){
        x[n]=X,f[n]=Y%mo;
        rep(i,1,n)f[n-i]=(f[n-i+1]-f[n-i])%mo*fpow((x[n]-x[n-i])%mo,mo-2)%mo;
        d[n++]=f[0];
    }
    ll operator () (ll X)const{
        ll ans=0,t=1;
        rep(i,0,n-1)ans=(ans+d[i]*t)%mo,t=(X-x[i])%mo*t%mo;
        return ans+mo*(ans<0);
    }
};
//检验线性递推数列的通项公式是否为多项式,C为递推公式
bool polyCheck(const vector<ll> &C){
    ll m=mo-C[1],last=1;
    rep(i,1,C.size()-1){
        last=last*(m-i+1)%mo*fpow(i,mo-2)%mo;
        if(last!=(i&1?(mo-C[i]):C[i]))return false;
    }
    return true;
}
//矩阵
class intMatrix{
public:
    ll a[N][N],n,m;
    bool operator < (const intMatrix &b)const{
        rep(i,0,n-1)rep(j,0,m-1)if(a[i][j]!=b.a[i][j])return a[i][j]<b.a[i][j];
        return false;
    }
    bool operator == (const intMatrix &b)const{
        return !(*this<b) && !(b<*this);
    }
    static intMatrix Eye(ll n){
        intMatrix c;
        c.n=c.m=n;
        rep(i,0,n-1)rep(j,0,n-1)c.a[i][j]=i==j;
        return c;
    }
    intMatrix operator * (const intMatrix &b)const{
        assert(m==b.n);
        intMatrix c;
        c.n=n,c.m=b.m;
        rep(i,0,c.n-1)rep(j,0,c.m-1)c.a[i][j]=0;
        rep(i,0,c.n-1)rep(j,0,c.m-1)rep(k,0,m-1)c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%mo;
        return c;
    }
    intMatrix operator ^ (int t)const{
        assert(n==m);
        intMatrix c=Eye(n),b=*this;
        while(t){if(t&1)c=c*b;b=b*b;t>>=1;}
        return c;
    }
    void print()const{
        rep(i,0,n-1)rep(j,0,m-1)cout<<a[i][j]<<" \n"[j==m-1];
        cout<<endl;
    }
};
//求同余意义下不依赖初值的周期,C为递推公式,d为步长
ll periodSolve(const vector<ll> &C,ll d){
    static map<intMatrix,ll> tab;
    tab.clear();
    ll k=C.size()-1;
    assert(C[k]!=0);
    intMatrix A,B,T=intMatrix::Eye(k),D=T;
    A.n=A.m=B.n=B.m=k;
    rep(i,0,k-1)rep(j,0,k-1)A.a[i][j]=j==0?((C[i+1]>0)*mo-C[i+1]):(i==j-1);
    rep(i,0,k-1)rep(j,0,k-1)B.a[i][j]=j==k-1?((mo-C[i])*fpow(C[k],mo-2)%mo):(i==j+1);
    rep(i,1,d){
        T=T*B;
        if(T==D)return i;
        tab[T]=i;
    }
    intMatrix Ad=A^d;
    ll x=0;
    while(1){
        if(tab.find(D)!=tab.end())return x*d+tab[D];
        D=D*Ad;
        x++;
    }
    return -1;
}
ll polySolve(const vector<ll> &s,const vector<ll> &C,ll n){
    if(n<s.size())return s[n];
    static ll g[N],f[N],d[N];
    ll k=(ll)C.size()-1,w=1;
    rep(i,0,k)f[i]=i==1,d[i]=i==k?1:C[k-i];
    while((w<<1)<=n)w<<=1;
    while(w>>=1){
        rep(i,0,k+k-2)g[i]=0;
        rep(i,0,k-1)if(f[i])rep(j,0,k-1)(g[i+j]+=f[i]*f[j])%=mo;
        for(ll i=k+k-2;i>=k;i--)if(g[i])rep(j,1,k)(g[i-j]-=g[i]*d[k-j])%=mo;
        rep(i,0,k-1)f[i]=g[i];
        if(w&n)for(ll i=k;i>=0;i--)f[i]=i==k?f[i-1]:(i==0?-f[k]*d[i]:(f[i-1]-f[k]*d[i]))%mo;
    }
    ll ans=0;
    rep(i,0,k-1)(ans+=f[i]*s[i])%=mo;
    return ans+(ans<0)*mo;
}
class Sequence{
public:
    ll poly;
    vector<ll> A,C;
    NewtonPoly P;
    void build(const vector<ll> &s){
        A=s;
        C=BM(A);
        poly=polyCheck(C);
        if(poly)rep(i,0,s.size()-1)P.add(i,s[i]);
    }
    ll operator () (ll n)const{
        return poly?P(n):polySolve(A,C,n);
    }
    friend ostream &operator << (ostream &o,const Sequence &b){
        o<<"f(n)";
        rep(i,1,b.C.size()-1)o<<"+("<<b.C[i]<<")*f(n-"<<i<<")";
        o<<"=0 (mod "<<mo<<")";
        return o;
    }
    ll period()const{
        ll M=periodSolve(C,(ll)sqrt(mo)),ans=M;
        return M;
        for(ll i=1;i*i<=M;i++)if(M%i==0){
            ll d=i,flag=1;
            rep(i,0,(ll)C.size()-2)if((*this)(d+i)!=A[i])flag=0;
            if(flag)ans=min(ans,d);
            d=M/i,flag=1;
            rep(i,0,(ll)C.size()-2)if((*this)(d+i)!=A[i])flag=0;
            if(flag)ans=min(ans,d);
        }
        return ans;
    }
}F;

int main(){
    ios::sync_with_stdio(false);
    F.build({1,1,2,3,5,8,13,21});
    cout<<F<<endl;
    F.build({0,1,4,9,16,25,36,49});
    cout<<F<<endl;
    F.build({0,1,5,15,35,70,126,210,330,495,715});
    cout<<F<<endl;
    F.build({0,1,2,0,1,2,0,1,2});
    cout<<F<<endl;
    F.build({0,1,1,2,4,7,13});
    cout<<F<<endl;
    return 0;
}

你可能感兴趣的:(模板,ACM中的数学问题合集)