2019牛客暑期多校训练营5B:generator 1
Fn = aFn-1 + bFn-2 ,给出Fn数列的前两项F0和F1,求Fn【n大到要用字符串输入】
(1)十进制矩阵快速幂
递推式直接给出了,但N大的我不敢写矩阵快速幂,赛后了解到十进制矩阵快速幂,原理和二进制一样:比如求矩阵A^123,等价于计算:A^100 * A^20 * A^3 = (A^100)^1 * (A^10)^2 * (A^1)^3,括号里的就和二进制每次平方是一样的道理
代码:
#include
#define sz(x) (x).size()
using namespace std;
typedef long long ll;
struct matrix{
ll m[2][2];
};
matrix I = {1,0,0,1};
ll x0,x1,a,b,mod;
string s;
inline matrix operator * (const matrix &A,const matrix &B){
matrix res;
res.m[0][0] = (A.m[0][0]*B.m[0][0]+A.m[0][1]*B.m[1][0])%mod;
res.m[0][1] = (A.m[0][0]*B.m[0][1]+A.m[0][1]*B.m[1][1])%mod;
res.m[1][0] = (A.m[1][0]*B.m[0][0]+A.m[1][1]*B.m[1][0])%mod;
res.m[1][1] = (A.m[1][0]*B.m[0][1]+A.m[1][1]*B.m[1][1])%mod;
return res;
}
matrix qpow(matrix A,int x){
matrix res = I;
while(x){
if(x&1) res = A*res;
A = A*A;
x >>= 1;
}
return res;
}
ll solve(){
matrix A = {a,b,1,0},B = {x1,0,x0,0};
for(int i = sz(s)-1; ~i; --i){
if(s[i]-'0'){
matrix t = qpow(A,s[i]-'0');
B = t*B;
}
A = qpow(A,10);
}
return B.m[1][0];
}
int main(){
cin >> x0 >> x1 >> a >> b >> s >> mod;
cout << solve() << '\n';
return 0;
}
(2)找广义斐波拉契数列F[n]=aF[n-1]+bF[n-2]在模mod意义下的循环节
找循环节的方法来自:广义斐波拉契数列循环节
这里就存个板子(估计以后也用不上)
代码:
#include
#define sz(x) (int)(x).size()
using namespace std;
typedef unsigned long long LL;
const int maxn = 1e4+15;
struct matrix{
LL m[2][2];
};
matrix I = {1,0,0,1};
LL x0,x1,a,b,mod,prime[maxn],num[maxn];
string s;
LL qmul(LL a,LL b,LL mod){
LL res = 0;
while(b){
if(b & 1) res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res;
}
LL qpow(LL a,LL x,LL mod){
LL res = 1; a %= mod;
while(x){
if(x&1) res = res*a%mod;
a = a*a%mod;
x>>=1;
}
return res;
}
int Legendre(LL a,LL p,LL mod){
if(qpow(a,(p-1)>>1,mod)==1) return 1;
else return -1;
}
int getPrime(LL x){
int cnt = 0;
for(LL i = 2;i*i<=x; ++i){
if(x%i == 0){
prime[cnt] = i;
while(x%i==0) num[cnt]++,x/=i;
cnt++;
}
}
if(x>1) prime[cnt]=x,num[cnt++]=1;
return cnt;
}
LL lcm(LL a,LL b){
return a/__gcd(a,b)*b;
}
LL getlen(LL a,LL b,LL mod){ //得到F[n]=aF[n-1]+bF[n-2]在模mod意义下的循环节
int cnt = getPrime(mod);
LL res = 1,c = a*a+4*b;
for(int i = 0;i < cnt; ++i){
LL p = 1;
if(prime[i] == 2) p = 12;
else if(c%prime[i] == 0) p = prime[i]*(prime[i]-1);
else if(Legendre(c,prime[i],prime[i])==1) p = prime[i]-1;
else p = (prime[i]-1)*(prime[i]+1);
for(int j = 1;j < num[i]; ++j) p *= prime[i];
res = lcm(res,p);
}
return res;
}
inline matrix operator * (const matrix &A,const matrix &B){
matrix res;
res.m[0][0] = (A.m[0][0]*B.m[0][0]+A.m[0][1]*B.m[1][0])%mod;
res.m[0][1] = (A.m[0][0]*B.m[0][1]+A.m[0][1]*B.m[1][1])%mod;
res.m[1][0] = (A.m[1][0]*B.m[0][0]+A.m[1][1]*B.m[1][0])%mod;
res.m[1][1] = (A.m[1][0]*B.m[0][1]+A.m[1][1]*B.m[1][1])%mod;
return res;
}
LL solve(LL x){
matrix A = {a,b,1,0},B = {x1,0,x0,0};
while(x){
if(x & 1) B = A*B;
A = A*A;
x >>= 1;
}
return B.m[1][0];
}
LL cal(LL MOD){
LL res = 0;
for(int i = 0;i < sz(s); ++i) res = (qmul(res,10,MOD)+(s[i]-'0'))%MOD;
return res;
}
int main(){
cin >> x0 >> x1 >> a >> b >> s >> mod;
cout << solve(cal(getlen(a,b,mod))) << '\n';
return 0;
}