generator 1
题目描述
You are given four positive integers x_0, x_1, a, bx0,x1,a,b. And you know x_i = a \cdot x_{i-1} + b \cdot x_{i-2}xi=a⋅xi−1+b⋅xi−2 for all i \ge 2i≥2.
Given two positive integers n, and MOD, please calculate x_nxn modulo MOD.
Does the problem look simple? Surprise! The value of n may have many many digits!
输入描述:
The input contains two lines. The first line contains four integers x_0, x_1, a, bx0,x1,a,b (1 \le x_0, x_1, a, b \le 10^91≤x0,x1,a,b≤109). The second line contains two integers n, MOD (1 \le n < 10^{(10^6)}, 10^9 < MOD \le 2 \times 10^91≤n<10(106),109<MOD≤2×109, n has no leading zero).
输出描述:
Print one integer representing the answer.
示例1
输入
1 1 1 1 10 1000000001
输出
89
说明
The resulting sequence x is Fibonacci sequence. The 11-th item is 89.
示例2
输入
1315 521 20185 5452831 9999999999999999999999999999999999999 1000000007
输出
914730061
题意:f(n) = a * f(n - 1) + b * f(n - 2),给一个 n ,求 f(n) ,n 的位数最长为 1e6
思路:n 特别大,如果用二进制快速幂是会T的,因为 logn 就是 1e6,还需要算上大数取模和大数除的复杂度。
Code:
#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fir first
#define sec second
#define CLR(a) while(!(a).empty()) a.pop()
using namespace std;
const int maxn = 3;
LL mod;
struct mat{
LL m[maxn][maxn];
LL n; //n为输入的矩阵大小
mat(LL _Size) {
memset(m, 0, sizeof m);
n = _Size;
}
inline void set() {
memset(m, 0, sizeof m);
for(int i = 1;i <= n;++ i) m[i][i] = 1;
}
inline mat operator * (const mat &B) const{ // 计算矩阵 A * B, 放入C
mat C = mat(n);
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= n;j ++){
for(int x = 1;x <= n;x ++)
C.m[i][j] = (C.m[i][j] + m[i][x] * B.m[x][j]) % mod;
}
return C;
}
inline mat operator ^ (LL coun){ // 矩阵快速幂, 矩阵A的 coun次幂
mat C = mat(n),A = *this;
C.set();
while(coun > 0){
if(coun & 1) C = C * A;
A = A * A;
coun >>= 1;
}
return C;
}
};
mat quick_mat(mat A,char* c){
mat C = mat(2);
C.set();
int t = strlen(c); -- t;
while(t >= 0){
LL cnt = c[t] - '0';
mat tmp = A;
while(cnt){
if(cnt & 1) C = C * tmp;
tmp = tmp * tmp;
cnt >>= 1;
}
A = A ^ 10;
-- t;
}
return C;
}
char tmp[1000010],nn[1000010]; /// 减
int c[1000010],d[1000010],f[1000010];
void bigjian(char *a, char *b) {
int i = strlen(a) - 1, j = strlen(b) - 1;
int x = 0, flag = 1;
for(int l = 0; l <= i; l++)
c[l] = a[l] - '0';
for(int l = 0; l <= j; l++)
d[l] = b[l] - '0';
while(j != -1) {
if(c[i] < d[j]) {
c[i] += 10;
c[i - 1] -= 1;
}
f[x++] = c[i] - d[j];
i--;
j--;
}
while(i >= 0) {
if(c[i] < 0) {
c[i] += 10;
c[i - 1] -= 1;
}
f[x++] = c[i];
i--;
}
int p = 0;
if(f[x - 1] == 0)
flag = 0;
for(int y = x - 1; y >= 0; y--) {
if(f[y] != 0)
flag = 1;
if(flag == 1)
tmp[p ++] = f[y] + '0';
}
if(flag == 0)
tmp[p ++] = '0';
tmp[p] = '\0';
}
int main() {
LL x0,x1,a,b; scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b);
scanf("%s%lld",nn,&mod);
mat A = mat(2);
A.m[1][1] = a; A.m[1][2] = 1LL;
A.m[2][1] = b; A.m[2][2] = 0LL;
mat B = mat(2);
B.m[1][1] = x1; B.m[1][2] = x0;
bigjian(nn,"1");
A = quick_mat(A,tmp);
B = B * A;
printf("%lld\n",B.m[1][1]);
return 0;
}