标签:表示 eof -- 转化 data 自然数 highlight 计算 typedef
题目描述
输入
输出
样例输入
2
1 1
1 1
2 10 1000003
样例输出
142
题解
裸的矩乘快速幂,转移矩阵都给出来了。
将区间求和转化为前缀相减处理,对于矩阵[a1 a2 ... ak],按照题目中的公式推出[a2 a3 ... ak+1],然后由于求和,所以需要再开一个位置记录前缀和。
转移矩阵自己推一推就好了。
注意特判t<=k的情况。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; int n; ll p , sum[20]; struct data { ll v[20][20]; data() {memset(v , 0 , sizeof(v));} data operator*(const data a)const { data ans; int i , j , k; for(i = 1 ; i <= n ; i ++ ) for(j = 1 ; j <= n ; j ++ ) for(k = 1 ; k <= n ; k ++ ) ans.v[i][j] = (ans.v[i][j] + v[i][k] * a.v[k][j]) % p; return ans; } data operator^(const ll a)const { data x = *this , ans; int y = a , i; for(i = 1 ; i <= n ; i ++ ) ans.v[i][i] = 1; while(y) { if(y & 1) ans = ans * x; x = x * x , y >>= 1; } return ans; } }B , A; ll cal(ll t) { if(t < n) return sum[t]; return (B * (A ^ (t - n + 1))).v[1][n]; } int main() { int i , j; ll l , r; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &B.v[1][i]) , B.v[1][n + 1] = B.v[1][n + 1] + B.v[1][i] , sum[i] = sum[i - 1] + B.v[1][i]; for(i = n ; i >= 1 ; i -- ) scanf("%lld" , &A.v[i][n]) , A.v[i][n + 1] = A.v[i][n]; for(i = 1 ; i < n ; i ++ ) A.v[i + 1][i] = 1; n ++ , A.v[n][n] = 1; scanf("%lld%lld%lld" , &l , &r , &p); for(i = 1 ; i < n ; i ++ ) sum[i] %= p; for(i = 1 ; i <= n ; i ++ ) for(j = 1 ; j <= n ; j ++ ) A.v[i][j] %= p , B.v[i][j] %= p; printf("%lld\n" , (cal(r) - cal(l - 1) + p) % p); return 0; }
【bzoj3231】[Sdoi2008]递归数列 矩阵乘法+快速幂
标签:表示 eof -- 转化 data 自然数 highlight 计算 typedef
原文地址:http://www.cnblogs.com/GXZlegend/p/7113019.html