hdu 6198 【BM求线性递推】【模板】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6198
思路:先手推出前几项,然后直接套用模板就 o k {ok} ok了。
模板真好用。。。。
AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll qpow(ll x,ll y)
{
    ll ans=1;
    x%=mod;
    while(y){
        if(y&1)
            ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}
typedef vector<int> VI;
namespace linear_seq{
    const int n = 10010;
    ll res[n], base[n], c[n], md[n];
    vector < int > Md;
    void mul( ll *a, ll *b, int k){
        for (int i=0; i<k+k; i++){
            c[i]=0;
        }
        for (int i=0; i<k; i++){
            if ( a[i] ){
                for (int j=0; j<k; j++){
                    c[i+j]=(c[i+j] + a[i] * b[j])% mod;
                }
            }
        }
        for (int i=k+k-1; i>=k; i--){
            if ( c[i] ){
                for (int j=0; j < (int)Md.size(); j++){
                    c[ i-k+Md[j] ] = (c[ i-k+Md[j] ] - c[i] * md[ Md[j] ])%mod;
                }
            }
        }
        for (int i=0; i<k; i++){
            a[i]=c[i];
        }
    }

    ll solve(ll n, VI a, VI b){
        ll ans=0, pnt=0;
        int k=(int)a.size();
        assert((int)a.size()==(int)b.size());
        for (int i=0; i<k; i++){
            md[k-1-i]=-a[i];
        }
        md[k]=1;
        Md.clear();
        for (int i=0; i<k; i++){
            if ( md[i] != 0){
                Md.push_back(i);
            }
        }
        for (int i=0; i<k; i++){
            res[i] = base[i] = 0;
        }
        res[0]=1;
        while ( ( 1|1 << pnt) <= n ){
            pnt++;
        }
        for (int p=pnt; p>=0; p--){
            mul( res, res, k);
            if ( (n>>p) & 1){
                for (int i=k-1; i>=0; i--){
                    res[i+1]=res[i];
                }
                res[0]=0;
                for (int j=0; j< (int) Md.size(); j++){
                    res[ Md[j] ]=(res[ Md[j] ]- res[k] * md[ Md[j] ] )%mod;
                }
            }
        }
        for (int i=0; i<k; i++){
            ans=( ( ans + res[i] * b[i] )%mod + mod )%mod;
        }
        return ans;
    }
    VI BM(VI s){
        VI C(1,1), B(1,1);
        int L=0, m=1, b=1;
        for (int n=0; n<(int)s.size(); n++){
            ll d=0;
            for (int i=0; i<L+1; i++){
                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*qpow( b, mod-2)%mod;
                while ((int)C.size() < (int)B.size()+m){
                    C.push_back(0);
                }
                for (int i=0; i<(int)B.size(); i++){
                    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*qpow(b, mod-2)%mod;
                while ((int)C.size()<(int)B.size()+m){
                    C.push_back(0);
                }
                for (int i=0; i<(int)B.size(); i++){
                    C[i+m]= ( C[i+m] + c*B[i] )%mod;
                }
                m++;
            }
        }
        return C;
    }
    ll gao( VI a, ll n){
        VI c=BM( a );
        c.erase( c.begin() );
        for (int i=0; i<(int)c.size(); i++){
            c[i]= ( mod -c[i] )%mod;
        }
        return solve( n, c, VI( a.begin(), a.begin() + (int)c.size() ) );
    }
};
int main()
{
    VI a;
    int N,v;
    a.push_back(4);
    a.push_back(12);
    a.push_back(33);
    a.push_back(88);
    a.push_back(232);
    a.push_back(609);
    a.push_back(1596);
    ll n;
    while (~scanf("%lld",&n)){
        ll ans=linear_seq::gao(a,n-1);
        printf("%lld\n",ans);
    }
    return 0;
}

算法参考:https://zerol.me/2018/02/06/linearly-recurrent-sequence/
我一定可以的!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值