[BZOJ3231][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
由四行组成。
第一行是一个自然数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
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$