luogu2461递归数列

题目描述

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

对于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的余数的值。

输入输出格式

输入格式:
输入文件spp.in由四行组成。
第一行是一个自然数k。
第二行包含k个自然数b1, b2,…,bk。
第三行包含k个自然数c1, c2,…,ck。
第四行包含三个自然数m, n, p。

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

输入输出样例

输入样例#1:
2
1 1
1 1
2 10 1000003

输出样例#1:
142

说明

对于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

这里写图片描述

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long 

using namespace std;

const int N=20;
int k;
LL n,mm,mod;
LL b[N],c[N];
LL tot=0;

struct node{
    LL m[N][N];
    node operator *(const node &a) const{
        node ans;
        for (int i=1;i<=k;i++)
            for (int j=1;j<=k;j++)
            {
                ans.m[i][j]=0;
                for (int l=1;l<=k;l++)
                    ans.m[i][j]=(ans.m[i][j]+m[i][l]*a.m[l][j])%mod;
            }
        return ans;  ///
    }
    void clear()
    {
        memset(m,0,sizeof(m));
    }
    LL KSM(LL pp)
    {
        LL p;
        if (pp<=k)  //用不到矩乘 
        {
            LL an=0;
            for (int i=1;i<=pp;i++)  //直接暴力 
                an=(an+b[i])%mod;
            return an%mod;
        }
        p=pp-k; //真心。。对样例调一调就好了 
        node ans=(*this),a=(*this);
        while (p)
        {
            if (p&1)
               ans=ans*a;
            a=a*a;
            p>>=1;
        }
        LL r=0;
        for (int i=1;i<k;i++)
            r=(r+(ans.m[i][k]*b[k-i])%mod)%mod;  //计算前缀和 
        r=(r+(tot*ans.m[k][k])%mod)%mod;
        return r;  //sum
    }
};

int main()
{
    scanf("%d",&k);
    for (int i=1;i<=k;i++) scanf("%lld",&b[i]); 
    for (int i=1;i<=k;i++) scanf("%lld",&c[i]);
    scanf("%lld%lld%lld",&mm,&n,&mod);
    for (int i=1;i<=k;i++) tot=(tot+b[i]%mod)%mod;  //tot前缀和 
    node m,t;
    m.clear(); t.clear();
    for (int i=1;i<=k;i++)   //矩阵的初始值 
    { //在矩阵中我们要维护一个前缀和 
        m.m[i][1]=c[i];
        m.m[i][k+1]=c[i];
        t.m[i][1]=c[i];
        t.m[i][k+1]=c[i];
    }
    for (int i=1;i<k;i++) m.m[i][i+1]=1,t.m[i][i+1]=1;
    m.m[k+1][k+1]=1;
    t.m[k+1][k+1]=1;
    k++;
    LL an=0;
    an+=m.KSM(n);
    an-=t.KSM(mm-1);
    printf("%lld",(an+mod)%mod);  //题目有漏洞,在最后的%处理时要先+mod再% 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值