开始玩矩阵了!先来一道入门题![SDOI2008]递归数列
Posted cc123321
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了开始玩矩阵了!先来一道入门题![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的值。
输入输出样例
说明
对于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; }
以上是关于开始玩矩阵了!先来一道入门题![SDOI2008]递归数列的主要内容,如果未能解决你的问题,请参考以下文章
[bzoj2049][Sdoi2008]Cave 洞穴勘测_LCT
bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门
可恶!学了这么久的LCA,联考的题目却是LCA+树形DP!!!可恶|!!!这几天想学学树形DP吧!先来一道入门题HDU 1520 Anniversary party