UVA10655 Contemplation! Algebra —— 推公式、矩阵快速幂

题目链接:https://vjudge.net/problem/UVA-10655

题意:

a+b、ab的值分别为p、q,求a^n+b^n。

题解:

1.a、b未知,且直接求出a、b也不太实际。

2.看到 a^n+b^n 这个式子就想到二阶齐次递推式的通项公式,然后就想是否能通过通项公式反推回递推式。结果发现a、b的值是不能确定是否相等的,而求二阶齐次递推式的通项公式时,是需要根据根的情况来分类求解的,所以此题不适应。

3.那么,就直接对 a^n+b^n 做一下变形:

4.得到递推式之后,就直接构造矩阵,然后快速幂。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 1e6+100;
18 
19 const int Size = 2;
20 struct MA
21 {
22     LL mat[Size][Size];
23     void init()
24     {
25         for(int i = 0; i<Size; i++)
26         for(int j = 0; j<Size; j++)
27             mat[i][j] = (i==j);
28     }
29 };
30 
31 MA mul(MA x, MA y)
32 {
33     MA ret;
34     memset(ret.mat, 0, sizeof(ret.mat));
35     for(int i = 0; i<Size; i++)
36     for(int j = 0; j<Size; j++)
37     for(int k = 0; k<Size; k++)
38         ret.mat[i][j] += 1LL*x.mat[i][k]*y.mat[k][j];
39     return ret;
40 }
41 
42 MA qpow(MA x, LL y)
43 {
44     MA s;
45     s.init();
46     while(y)
47     {
48         if(y&1) s = mul(s, x);
49         x = mul(x, x);
50         y >>= 1;
51     }
52     return s;
53 }
54 
55 
56 int main()
57 {
58     LL p, q, n, f[2];
59     while(scanf("%lld%lld%lld", &p,&q,&n)==3)
60     {
61         f[0] = 2; f[1] = p;
62         if(n<=1)
63         {
64             printf("%lld
", f[n]);
65             continue;
66         }
67 
68         MA s;
69         memset(s.mat, 0, sizeof(s.mat));
70         s.mat[0][0] = p; s.mat[0][1] = -q;
71         s.mat[1][0] = 1; s.mat[1][1] = 0;
72 
73         s = qpow(s, n-1);
74         LL ans = 1LL*s.mat[0][0]*f[1] + 1LL*s.mat[0][1]*f[0];
75         printf("%lld
", ans);
76     }
77 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8426209.html