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

[SDOI2008]递归数列

题目描述

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

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

挺水的一道题,推出了矩阵,然后前缀和搞搞也就简单了;

矩阵如下:

S[n]
b[n]
b[n-1]
...
b[n-k+1]
=
1 c[1] ... c[k-1] c[k]
0 c[1] ... c[k-1] c[k]
0 1 ... 0 0
0 0 ... 0 0
0 0 ... 1 0
*
 
S[n-1]
b[n-1]
b[n-2]
...
b[n-k+1]

 

#include<bits/stdc++.h>
#define ll long long
#define maxn 20
using namespace std;

ll k,b[maxn],c[maxn],n,m,p,tot;

struct mat{
    ll x,y;
    ll s[maxn][maxn];
};

mat operator *(mat a,mat b)
{
    mat c;
    c.x = a.x;
    c.y = b.y;
    memset(c.s,0,sizeof(c.s));
    for(ll i=1;i<=a.x;i++)
        for(ll j=1;j<=b.y;j++)
            for(ll k=1;k<=b.x;k++)
                c.s[i][j] = (c.s[i][j] + a.s[i][k] * b.s[k][j] % p) % p;
    return c;
}

mat ksm(mat a,ll ci)
{
    mat ans;
    memset(ans.s,0,sizeof(ans.s));
    ans.x = ans.y = a.x;
    for(ll i=1;i<=ans.x;i++)
        ans.s[i][i] = 1;
    while(ci)
    {
        if(ci & 1) ans = ans * a;
        a = a * a;
        ci >>= 1;
    }
    return ans;
}

ll find(ll num)
{
    if(num <= k)
    {    
        ll ans = 0;
        for(ll i=1;i<=num;i++) ans += b[i],ans %= p;
        return ans % p;
    }
    mat ans;
    memset(ans.s,0,sizeof(ans.s));
    ans.x = ans.y = k + 1;
    for(ll i=2;i<=k+1;i++)
        ans.s[1][i] = ans.s[2][i] = c[i - 1];
    ans.s[1][1] = 1;
    for(ll i=2;i<=k;i++)
        ans.s[i + 1][i] = 1;
    ans = ksm(ans , num - k);
    mat right;
    memset(right.s,0,sizeof(right.s));
    right.x = k + 1;
    right.y = 1;
    for(ll i=2;i<=k+1;i++)
        right.s[i][1] = b[k + 2 - i];
    right.s[1][1] = tot;
    right = ans * right;
    return right.s[1][1];
}

int main(){
    cin >> k;
    for(ll i=1;i<=k;i++) scanf("%d",&b[i]),tot += b[i];
    for(ll i=1;i<=k;i++) scanf("%d",&c[i]);
    cin >> m >> n >> p;
    cout << (find(n) - find(m - 1) + p) % p;
}

 

 

posted @ 2017-10-27 20:30  cc123321  阅读(282)  评论(0编辑  收藏  举报