[luogu2461 SDOI2008] 递归数列 (矩阵乘法)

Posted menteur-hxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu2461 SDOI2008] 递归数列 (矩阵乘法)相关的知识,希望对你有一定的参考价值。

传送门

Description

一个由自然数组成的数列按下式定义:

对于i <= k:ai = bi

对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai-k

其中bj 和 cj (1<=j<=k)是给定的自然数。写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + ... + an, 并输出它除以给定自然数p的余数的值。

Input

输入文件spp.in由四行组成。

第一行是一个自然数k。

第二行包含k个自然数b1, b2,...,bk。

第三行包含k个自然数c1, c2,...,ck。

第四行包含三个自然数m, n, p。

Output

输出文件spp.out仅包含一行:一个正整数,表示(am + am+1 + am+2 + ... + an) mod p的值。

Sample Input

2
1 1
1 1
2 10 1000003

Sample Output

142

HINT

对于100%的测试数据:

1<= k <=15

1 <= m <= n <= 1018

对于20%的测试数据:

1<= k <=15

1 <= m <= n <= 106

对于30%的测试数据:

k=1 1 <= m <= n <= 1018

对于所有测试数据:

0<= b1, b2,... bk, c1, c2,..., ck<=109

1 <= p <= 108

Solution

构造矩阵然后直接乘
注意乘的顺序还有最后一定要再MOD一次以防万一qwq

Code

//By Menteur_Hxy
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
typedef long long LL;

LL read() {
    LL x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}

const int K=20;
int k;
int c[K],b[K];
LL n,m,MOD,ans1,ans2,s[K];
struct Matrix{
    LL da[K][K];
    Matrix() {clear();};
    void clear() {memset(da,0,sizeof(da));}
    Matrix operator * (const Matrix oth) {
        Matrix res; 
        F(i,0,k) F(j,0,k) F(l,0,k) 
            res.da[i][j]=(res.da[i][j]+oth.da[i][l]*da[l][j]%MOD)%MOD;
        return res;
    }
    void print() {
        F(i,0,k) {
            F(j,0,k) cout<<da[i][j]<<" ";
            cout<<endl;
        }cout<<endl;
    }
}ans,st;

Matrix Qpow(Matrix a,LL d) {
    Matrix ret;
    ret.da[0][0]=s[k];
    F(i,1,k) ret.da[i][0]=b[k-i+1];
    while(d) {
        if(d&1) ret=ret*a;
        a=a*a; d>>=1;
//      a.print();
    }
    return ret;
}

int main() {
    k=read();
    F(i,1,k) b[i]=read(),s[i]=s[i-1]+b[i];
    F(i,1,k) c[i]=read();
    m=read(),n=read(),MOD=read();
    st.da[0][0]=1;
    F(i,1,k) st.da[0][i]=st.da[1][i]=c[i];
    F(i,2,k) st.da[i][i-1]=1;
//  st.print();
    if(n<=k) {
        printf("%lld",s[n]-s[m-1]);
        return 0;
    } else {
        ans=Qpow(st,n-k);
//      ans.print();
        ans1=ans.da[0][0];
    }
    if(m<=k) ans2=s[m-1];
    else {
        ans=Qpow(st,m-k-1);
//      ans.print();
        ans2=ans.da[0][0];
    }
    printf("%lld",(ans1-ans2+MOD)%MOD);
    return 0;
}

以上是关于[luogu2461 SDOI2008] 递归数列 (矩阵乘法)的主要内容,如果未能解决你的问题,请参考以下文章

[SDOI2008]递归数列

开始玩矩阵了!先来一道入门题![SDOI2008]递归数列

bzoj 3231: [Sdoi2008]递归数列矩阵乘法

bzoj3231[Sdoi2008]递归数列 矩阵乘法+快速幂

luogu_2158 [SDOI2008]仪仗队

luogu P1984 [SDOI2008]烧水问题