题目 | Geometric Progression
AtCoder Beginner Contest 293
E - Geometric Progression
https://atcoder.jp/contests/abc293/tasks/abc293_e
Time Limit: 2 sec / Memory Limit: 1024 MB
Score :
Problem Statement
Given integers
Constraints
- All values in the input are integers.
Input
The input is given from Standard Input in the following format:
Output
Print the answer.
Sample Input 1
3 4 7
Sample Output 1
5
Sample Input 2
8 10 9
Sample Output 2
0
Sample Input 3
1000000000 1000000000000 998244353
Sample Output 3
919667211
题解
典型错解——使用等比数列求和公式
我们知道等比数列求和公式:
那么易得:
其中,
要求
当
与 互质- 可用扩展欧几里得算法得出:
- 特别的,当
为质数,可用费马小定理得出:
- 可用扩展欧几里得算法得出:
当
与 不互质 对于模 不存在乘法逆元
由题目可知,没有对
正确解法——矩阵加速递推
构造递推
令
若直接进行递推,时间复杂度
加速递推
将上述递推式改写为矩阵形式:
那么我们的递推式就能变成矩阵次幂形式了:
同时,矩阵的次幂也是可以使用快速幂的,因为矩阵乘法也满足
题目的答案便是
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<vector<ll>> mat_mul_2d(vector<vector<ll>> a, vector<vector<ll>> b, ll p)
{
vector<vector<ll>> ans(2, vector<ll>(2));
ans[0][0] = ((a[0][0] * b[0][0]) % p + (a[0][1] * b[1][0]) % p) % p;
ans[0][1] = ((a[0][0] * b[0][1]) % p + (a[0][1] * b[1][1]) % p) % p;
ans[1][0] = ((a[1][0] * b[0][0]) % p + (a[1][1] * b[1][0]) % p) % p;
ans[1][1] = ((a[1][0] * b[0][1]) % p + (a[1][1] * b[1][1]) % p) % p;
return ans;
}
vector<vector<ll>> mat_fastpow_2d(vector<vector<ll>> a, ll n, ll p)
{
vector<vector<ll>> ans(2, vector<ll>(2));
ans[0][0] = ans[1][1] = 1;
while (n)
{
if (n % 2)
ans = mat_mul_2d(ans, a, p);
a = mat_mul_2d(a, a, p);
n >>= 1;
}
return ans;
}
void solve()
{
ll A, X, M;
cin >> A >> X >> M;
vector<vector<ll>> mat = {{A, 1}, {0, 1}};
vector<vector<ll>> ans = mat_fastpow_2d(mat, X, M);
cout << ans[0][1] << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi