矩阵快速幂-CodeForces 450B Jzzhu and Sequences

矩阵快速幂-CodeForces 450B Jzzhu and Sequences 题目:
Jzzhu has invented a kind of sequences, they meet the following property:
矩阵快速幂-CodeForces 450B Jzzhu and Sequences
文章图片

You are given x and y, please calculate fn modulo 1000000007 (109?+?7).
Input
The first line contains two integers x and y (|x|,?|y|?≤?109). The second line contains a single integer n (1?≤?n?≤?2·109).
Output
Output a single integer representing fn modulo 1000000007 (109?+?7).
Examples
Input
2 3
3
Output
1
Input
0 -1
2
Output
1000000006
Note
In the first sample, f2?=?f1?+?f3, 3?=?2?+?f3, f3?=?1.
In the second sample, f2?=??-?1; ?-?1 modulo (109?+?7) equals (109?+?6).
题意:
满足上述递推式,输入f1和f2,再输入n,求fn=?
【矩阵快速幂-CodeForces 450B Jzzhu and Sequences】思路:
矩阵快速幂的模板题。
递推式满足:矩阵快速幂-CodeForces 450B Jzzhu and Sequences
文章图片

记关系矩阵为T=矩阵快速幂-CodeForces 450B Jzzhu and Sequences
文章图片

An=矩阵快速幂-CodeForces 450B Jzzhu and Sequences
文章图片

那么由T*A(n-1)=A(n) 容易得到A(n)=T(n-1) *A(1),于是问题只需求解矩阵Tn-1即可。
理解矩阵快速幂,先来看一看整数的快速幂:

int quieck_pow(ll a, int n) { ll ans = 1; while (n) { if (n & 1) ans = ans * a ; //n是奇数,就更新一次最终的ans a = a * a ; //底数a变为a^2 n >>= 1; //指数n/2 } returnans; }

也就是将an不断分解为(a(n/2))2来计算,时间复杂度从O(n)变成了O(logn)。
再来看矩阵快速幂:
ll s[N][N] = {1, 0, 0, 1}; //单位矩阵 void mat_pow(int n) //矩阵快速幂A^n { ll x[N][N] = {0, 1, -1, 1}; while (n) { if (n&1) mat_mod(s, x); //单位矩阵s可类比上述整数快速幂中ans=1 mat_mod(x, x); n >>= 1; } }

本题代码:
#include #include using namespace std; typedef long long ll; const ll mod = 1e9+7; const int N=2; //矩阵阶数 ll s[N][N] = {1, 0, 0, 1}; //单位矩阵void mat_mod (ll a[N][N], ll b[N][N])//矩阵乘法A*A { ll c[N][N]; memset(c, 0, sizeof(c)); for (int k = 0; k < N; k++) { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) c[i][j] = ((c[i][j] + a[i][k] * b[k][j]) % mod + mod) % mod; } memcpy(a, c, sizeof(c)); }void mat_pow(int n) //矩阵快速幂A^n { ll x[N][N] = {0, 1, -1, 1}; while (n) { if (n&1) mat_mod(s, x); mat_mod(x, x); n >>= 1; } }int main () { int x, y, n; scanf("%d%d%d", &x, &y, &n); if (n == 1) printf("%lld\n", (x % mod + mod) % mod); else { mat_pow(n-2); printf("%lld\n", ((x * s[1][0] % mod + y * s[1][1] % mod) % mod + mod) % mod); } return 0; }

当然,如果是考试比赛现场,能偷鸡也是极好的。
不难发现其中的规律,周期是6,对负数取模做个特殊处理即可。
#include #include #define ll long long using namespace std; const int N=1e7; const ll mod=1e9+7; ll a[N]; ll n; int main() { cin>>a[1]>>a[2]; for(int i=3; i<=6; i++) a[i]=a[i-1]-a[i-2]; a[0]=a[6]; //注意取模范围为0~5,需要给a[0]赋值 scanf("%lld",&n); if(a[n%6]<0)//负数取模 { while(a[n%6]<0) a[n%6]+=mod; printf("%lld\n",a[n%6]); } else printf("%lld\n",a[n%6]%mod); return 0; }

    推荐阅读