B.generator 1
You are given four positive integers x 0 , x 1 , a , b x_0, x_1, a, b x0,x1,a,b. And you know x i = a ⋅ x i − 1 + b ⋅ x i − 2 x_i = a \cdot x_{i-1} + b \cdot x_{i-2} xi=a⋅xi−1+b⋅xi−2 for all i ≥ 2 i \ge 2 i≥2.
Given two positive integers n, and MOD, please calculate x n x_n xn 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
,
b
x_0, x_1, a, b
x0,x1,a,b,a,b (
1
≤
x
0
,
x
1
,
a
,
b
≤
1
0
9
1 \le x_0, x_1, a, b \le 10^9
1≤x0,x1,a,b≤109 ).
The second line contains two integers n, MOD (
41
≤
n
<
1
0
(
1
0
6
)
41 \le n < 10^{(10^6)}
41≤n<10(106),
1
0
9
<
M
O
D
≤
2
×
1
0
9
10^9 < MOD \le 2 \times 10^9
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
题意
给你
x
0
x_0
x0、
x
1
x_1
x1、a、b、b、mod,根据
x
i
=
a
∗
x
i
−
1
+
b
∗
x
i
−
2
x_i=a∗x_{i−1}+b∗x_{i−2}
xi=a∗xi−1+b∗xi−2求出
x
n
x_n
xn
思路
一般看到这种题就会想到矩阵快速幂,但是这次的n太大了,所以要用十进制倍增来算,(第一种做法)。同时还可以用二进制快速幂优化它(第二种做法)。
- 矩阵快速幂的通项式
- 用十进制
设
(
a
b
1
0
)
\tbinom{a \ \ \ b}{1\ \ \ 0}
(1 0a b)为res
则可得
a
n
s
=
r
e
s
n
[
i
]
−
′
0
′
ans=res^{n[i]-'0'}
ans=resn[i]−′0′(n[i]用字符串储存n)
我们再设res =
r
e
s
10
(
i
−
1
)
res^{10(i-1)}
res10(i−1);
就是分解n为每一位,再去相乘。
如
r
e
s
298
=
r
e
s
1
∗
8
∗
r
e
s
10
∗
9
∗
r
e
s
100
∗
2
res^{298}=res^{1*8}*res^{10*9}*res^{100*2}
res298=res1∗8∗res10∗9∗res100∗2
计算每一位即可。
所以最后就是
len(n)→1
ans=ans*cul(res,n[i]-‘0’);
res=pow(res,10);
ac代码(1512ms):
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Maxn=1e6+10;
struct node{
ll mat[2][2];
};
ll x0,x1,a,b,mod;
node ans,O,tmp,z;
char n[Maxn];
node cul(node x,node y){ //矩阵乘法
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
z.mat[i][j]=0;
for(int k=0;k<2;k++)
z.mat[i][j]=(z.mat[i][j]+x.mat[i][k]*y.mat[k][j])%mod;
}
return z;
}
int main(){
int op;
scanf("%lld %lld %lld %lld %s %lld",&x0,&x1,&a,&b,n,&mod);
int len=strlen(n);
ans.mat[0][0]=ans.mat[1][1]=1;
tmp.mat[0][0]=a;
tmp.mat[0][1]=b;
tmp.mat[1][0]=1;
for(int i=len-1;i>=0;i--){
op=n[i]-'0';
for(int j=0;j<op;j++) ans=cul(ans,tmp); //矩阵乘法得res^op
O.mat[0][0]=O.mat[1][1]=1; //初等矩阵
O.mat[0][1]=O.mat[1][0]=0;
for(int j=0;j<10;j++) O=cul(O,tmp); //直接跑十遍,求res^10n
tmp=O;
}
printf("%lld\n",(x1*ans.mat[1][0]+x0*ans.mat[1][1])%mod);
return 0;
}
另一种写法(1800ms):
#include<bits/stdc++.h>
#define mes(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll mod;
char n[maxn];
struct Mat{
ll mat[4][4];
Mat(){
mes(mat,0);
}
void init(){
for(int i=1;i<=2;i++)
mat[i][i]=1;
}
Mat operator*(const Mat &a)const{ //矩阵乘法
Mat ans;
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
for(int k=1;k<=2;k++){
ans.mat[i][j]+=mat[i][k]*a.mat[k][j]%mod;
ans.mat[i][j]%=mod;
}
}
}
return ans;
}
};
Mat pow(Mat a, ll b){ //矩阵快速幂
Mat ans;
ans.init();
while(b){
if(b&1)
ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int main(){
ll a,b,x1,x0;
scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b);
scanf("%s%lld",n,&mod);
int len=strlen(n);
Mat ans; ans.init();
Mat res;
res.mat[1][1]=a;res.mat[1][2]=b;
res.mat[2][1]=1;
for(int i=len-1;i>=0;i--){
ans=ans*pow(res,n[i]-'0');
res=pow(res,10ll); //用快速幂跑
}
Mat f;
f.mat[1][1]=x1;
f.mat[2][1]=x0;
f=ans*f;
printf("%lld\n",f.mat[2][1]);
return 0;
}