zoukankan      html  css  js  c++  java
  • [BZOJ] 3231: [Sdoi2008]递归数列

    看起来就像一个加权的斐波那契数列变形!(这个权是倒序加的,没仔细读题正着构造了矩阵,卡着30分百思不得其解qwq,现在看来应该是k=1的30分)

    构造一个矩阵,就可以很方便地求出第n项,但是它要求一段区间和,就在矩阵上加一个前缀和,维护起来非常方便

    转移矩阵前n-1列用来继承上次2~n列的状态,第n列用来加权转移第n+1项,第n+1列和第n列转移基本相同,多一个继承前缀和。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define int long long
    using namespace std;
    
    inline int rd(){
        int ret=0,f=1;char c;
        while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
        while(isdigit(c))ret=ret*10+c-'0',c=getchar();
        return ret*f;
    }
    
    int num,n,m,mod;
    
    inline int M(int x){
        while(x<0ll) x+=mod;
        return x%mod;
    }
    
    const int MAXN=64;
    
    typedef long long ll;
    
    struct Mat{
        int a[MAXN][MAXN];
        Mat(){memset(a,0,sizeof(a));}
        Mat operator*(const Mat &rhs){
            Mat ret;
            for(int k=1;k<=num+1;k++){
                for(int i=1;i<=num+1;i++){
                    for(int j=1;j<=num+1;j++){
                        (ret.a[i][j]+=(1ll*a[i][k]*rhs.a[k][j])%mod)%=mod;
                    }
                }
            }
            return ret;
        }
    }e;
    
    void show(Mat x){
        cout<<"===============================
    ";
        for(int i=1;i<=num+1;i++){
            for(int j=1;j<=num+1;j++){
                cout<<x.a[i][j]<<" ";
            }
            cout<<endl;
        }
        cout<<"===============================
    ";
    }
    
    Mat pow(Mat x,ll y){
        Mat ret(e),base(x);
        while(y){
            if(y&1) ret=ret*base;
            base=base*base;
            y>>=1ll;
        }
        return ret;
    }
    
    
    
    int B[MAXN],C[MAXN];
    
    void init(){
        for(int i=1;i<=num+1;i++){
            e.a[i][i]=1;
        }
    }
    
    void solve(){
        Mat ori;
        int s=0ll;
        for(int i=1;i<=num;i++){
            ori.a[1][i]=B[i]%mod;s+=B[i];s%=mod;
        }
        ori.a[1][num+1]=s;
        Mat tra;
        for(int i=1;i<num;i++) tra.a[i+1][i]=1ll;
        for(int i=1;i<=num;i++) tra.a[i][num]=tra.a[i][num+1]=C[num-i+1];//!!
        tra.a[num+1][num+1]=1ll;
        Mat res=pow(tra,n-num);
        Mat ansn=ori*res,ansm;
        ll ans=ansn.a[1][num+1];
        if(m>num){
            res=pow(tra,m-num-1);
            ansm=ori*res;
            ans=M(ans-ansm.a[1][num+1]);
            printf("%lld
    ",ans);
        }else{
            for(int i=1;i<m;i++) ans=M(ans-B[i]);
            printf("%lld
    ",ans);
        }
    }
        
    
    signed main(){
        num=rd();
        for(int i=1;i<=num;i++) B[i]=rd();
        for(int i=1;i<=num;i++) C[i]=rd();
        m=rd();n=rd();mod=rd();
        ll tmp=0;
        if(n<=num){
            for(int i=m;i<=n;i++) (tmp+=B[i])%=mod;//
            printf("%lld
    ",tmp);
            return 0;
        }
        init();
        solve();
        return 0;
    }

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9376133.html

  • 相关阅读:
    文件和文件夹权限
    CentOS 8修改用户密码
    Linux新建用户默认设置
    二、工具类
    一、MyBatis 核心配置文件
    十一、容器总结
    十、Collections工具类
    九、集合与数组之间的转化
    八、TreeSet
    ※大神※
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9376133.html
Copyright © 2011-2022 走看看