[BZOJ3231][SDOI2008]递归数列

Description

一个由自然数组成的数列按下式定义:
对于i <= kai = 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

由四行组成。
第一行是一个自然数k
第二行包含k个自然数b1, b2,...,bk
第三行包含k个自然数c1, c2,...,ck
第四行包含三个自然数m, n, p

Output

仅包含一行:一个正整数,表示(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 <= 10^18

 

 


 

 

矩乘没跑了...

信心满满的交上去wa,cao没开long long;

又信心满满地交上去爆负数出来,woc?这为什么会有负数。

不管了+mod再%mod交上去,wocA了?

为什么会出负数...

其实就是前缀和,跑两次,一次是n-k,一次是m-k-1,然后把sum做差。

矩阵...不想写了...算了写写吧.

 0  1  0  0      a1       a2  

 0  0  1  0        a2        a3

 0  0  0  1           *   a3     =         a4

c4 c3 c2 c1       a4         a5

c4 c3 c2 1        sum                   sum'

这是k=4的情况...

还有要注意的是n或者m小于k,要特判。

 

 


 

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define int long long
inline int read(){
    #define gc getchar()
    int res=0;char ch=gc;
    while(!isdigit(ch))ch=gc;
    while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch^48);ch=gc;}
    return res;
}
int k, m, n, p;
int b[16], c[16];

struct Mat
{
    int a[19][19];
    Mat() {memset(a, 0, sizeof a);}
    inline void init(){for(int i=1;i<=18;i++)a[i][i] = 1;}
    friend Mat operator *(Mat x, Mat y)
    {
        Mat z;
        for (int k = 1 ; k <= 18 ; k ++)
            for (int i = 1 ; i <= 18 ; i ++)
                for (int j = 1 ; j <= 18 ; j ++)
                    z.a[i][j] = (z.a[i][j] + x.a[i][k] * y.a[k][j]) % p;
        return z;
    }
    friend Mat operator ^ (Mat x, int y)
    {
        Mat res;res.init();
        while(y)
        {
            if (y&1) res = res * x;
            x = x * x;
            y >>= 1;
        }
        return res;
    }
}l, r, A, B;
int qzh[20];
signed main()
{
    k = read();
    for (int i = 1 ; i <= k ; i ++) b[i] = read(), qzh[i] = qzh[i-1] + b[i];
    for (int i = 1 ; i <= k ; i ++) c[i] = read();
    m = read(), n = read(), p = read();
    for (int i = 1 ; i <= k ; i ++) b[i] %= p, c[i] %= p;
    
    for (int i = 1 ; i < k ; i ++) A.a[i][i+1] = 1;
    for (int i = 1 ; i <= k ; i ++) A.a[k][i] = c[k-i+1];
    for (int i = 1 ; i <= k ; i ++) A.a[k+1][i] = c[k-i+1]; 
    A.a[k+1][k+1] = 1;
    for (int i = 1 ; i <= k ; i ++) B.a[i][1] = b[i];
    B.a[k+1][1] = qzh[k] % p;
    
    if (m >= k + 1)l = (A ^(m - k - 1)) * B;
    r = (A ^ (n - k)) * B;
    
    if (m <= k) 
    {
        for (int i = 1 ; i <= k ; i ++) qzh[i] %= p;
        if (n <= k) printf("%lld\n", qzh[n] - qzh[m-1]);
        else printf("%lld\n", r.a[k+1][1] - qzh[m-1]);
        return 0;
    }
    
    printf("%lld\n", (r.a[k+1][1] - l.a[k+1][1] + p) % p);
    return 0;
}

 $\sum_{age=16}^{18} hardworking = success$

posted @ 2018-07-29 11:20  zZhBr  阅读(165)  评论(0编辑  收藏  举报