2019牛客多校训练 第五场 generator 1(矩阵快速幂,斐波那契)
题目
https://ac.nowcoder.com/acm/contest/885/B
题意
第一行给你四个数x0,x1,a,b.
所有的x满足这样一个表达式:Xi = aXi-1 + bXi-2 (i>1)(与斐波那契相似)
第二行给你两个数n,mod.
n有106位(只能当字符串存储),mod <= 2x109.
让你求Xn取mod的答案是多少。
题解
由于此题n的数据范围很大,而且又知道公式,所以可以很容易想到是矩阵快速幂的裸题,但由于n的范围很大,所以需将二进制的快速幂写法改为十进制。
公式如下:
注意:计算矩阵相乘的时候建议直接写成二维矩阵的大小,用for循环会TLE。
AC代码
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
ll mod;
struct Mat{
ll x[2][2];
Mat(){};
Mat(int a)
{
x[0][0]=1;
x[1][1]=1;
x[0][1]=0;
x[1][0]=0;
}
void cls()
{
mem(x,0);
}
friend Mat operator *(const Mat &a,const Mat &b)
{
Mat c;
c.cls();
// for(int i=0;i<2;i++)//TLE
// {
// for(int j=0;j<2;j++)
// {
// for(int k=0;k<2;k++)
// {
// c.x[i][j] += a.x[i][k]%mod * b.x[k][j]%mod;
// c.x[i][j] %= mod;
// }
// }
// }
ll tmp00=a.x[0][0]*b.x[0][0] % mod+a.x[0][1]*b.x[1][0] % mod;
ll tmp01=a.x[0][0]*b.x[0][1] % mod+a.x[0][1]*b.x[1][1] % mod;
ll tmp10=a.x[1][0]*b.x[0][0] % mod+a.x[1][1]*b.x[1][0] % mod;
ll tmp11=a.x[1][0]*b.x[0][1] % mod+a.x[1][1]*b.x[1][1] % mod;
c.x[0][0]=tmp00 % mod;
c.x[0][1]=tmp01 % mod;
c.x[1][0]=tmp10 % mod;
c.x[1][1]=tmp11 % mod;
return c;
}
friend Mat operator ^(Mat a,int n)
{
Mat ans = Mat(1);
while(n)
{
if(n&1)
ans = ans*a;
a = a*a;
n>>=1;
}
return ans;
}
};
char n[1000005];
int main()
{
ll x0,x1,a,b;
scanf("%lld %lld %lld %lld",&x0,&x1,&a,&b);
scanf("%s",n);
scanf("%lld",&mod);
int len = strlen(n);
Mat ans = Mat(1);
Mat base;
base.x[0][0]=a;
base.x[0][1]=b;
base.x[1][0]=1;
base.x[1][1]=0;
if(len==1)
{
if(n[0]=='0')
{
printf("%lld\n",x0%mod);
return 0;
}
else if(n[0]=='1')
{
printf("%lld\n",x1%mod);
return 0;
}
}
int temp = len-1;
while(1)// n-1
{
n[temp]--;
if(n[temp]<'0')
{
n[temp]+=10;
temp--;
}
else break;
}
for(int i=0;i<len;i++)
{
ans=ans^10;
ans=ans*(base^(n[i]-'0'));
}
printf("%lld\n",(x1*ans.x[0][0]+x0*ans.x[0][1])%mod);
}