描述
Yaoge买了n块鸡排,其中第n块鸡排的质量为M(n),同时其质量M(n)满足M(n)=f(n)2
已知f(n)=x*f(n-1)+y*f(n-2)。其中,f(0)=1,f(1)=1。
Yaoge希望你能帮他算出这些鸡排的总质量对10007取模后的结果。
输入
第一行输入一个T,表示有T组测试数据(T<=10000),
接下来T行每行输入3个数,n,x,y,(2<=n,x,y<=100000000);
输出
输出鸡排的总质量对10007取模后的结果
我的想法
一开始写这道题时以为只要注意一下余数加法和乘法的使用就好了,然而跑出来一直超时(3000ms都超了),于是周冬雨眉头一皱发现事情并不简单。于是想了很多提高速度的办法,终于在茫茫博客中看到了希望。
这道题主要运用的是以下几个点(萌新觉得C白学了)
余数
(a+b)%c=(a%c+b%c)%c;
( a*b )%c=(a%c*b%c)%c;
本题取模是通过除以一个较大的质数(像10007,1e9+7)使结果落在较好观察的int范围里,也能够保证结果的离散性。快速乘法
这是由于数据太大,在机器算乘法时很容易超出long的范围,而且乘法的效率相对加法也较低。于是将其中一个乘数b用二进制表示(11001什么的)。则a*b=a * (2^c1+2^c2+2^c3……),将乘法拆成较小的乘法再相加运算提高速率,再结合上述的余数操作让数据不超出范围。给出代码如下。矩阵快速幂
这和快速乘法类似,同样将A^n的次方数n用二进制表示并拆开计算,不同的则是此处乘法是矩阵乘法,结果矩阵res不是相加而是相乘。
#include<stdio.h>//快速乘法
#define m 10007
int main()
{
int a,b;
int res=0;
scanf("%d %d",&a,&b);
while(b)
{
if(b&1) //位运算,判断最后位是否为1
{
b--;
res=(res+a)%m; //实现加法
}
b=b/2;
a=(a*2)%m; //实现乘法
}
printf("%d\n",res);
return 0;
}
算法分析
有了以上的预备知识,本题就相对好解决了。首先我们看以下递推关系。
S(n) = ∑f(n)^2 = S(n-1)+f(n)^2 = S(n-1)+x^2 f(n-1)^2+y^2 f(n-2)^2+2xyf(n-1)f(n-2)
于是我们构造这样的矩阵方便计算(用矩阵快速幂)
用矩阵快速幂计算A^(n-1),我们所求的结果就是该矩阵第一行的和而已了(是不是很简单)
代码
#include<stdio.h>
#define m 10007
struct matrix //定义矩阵
{
int data[4][4];
};
struct matrix I={1,0,0,0, //单位阵
0,1,0,0,
0,0,1,0,
0,0,0,1};
int matpow(struct matrix c,int n); //矩阵快速幂函数
struct matrix mul(struct matrix a,struct matrix b);//矩阵乘法函数
int main()
{
int t,i;
scanf("%d",&t);
for(i=0;i<t;i++)
{
long long n,x,y;
scanf("%ld %ld %ld",&n,&x,&y);
x=x%m;y=y%m;
struct matrix a={1,(x*x)%m,(y*y)%m,(2*x*y)%m, //矩阵A
0,(x*x)%m,(y*y)%m,(2*x*y)%m,
0,1,0,0,
0,x,0,y};
printf("%d\n",(matpow(a,n-1))%m);
}
return 0;
}
struct matrix mul(struct matrix a,struct matrix b)
{
struct matrix ans=I;
int i,j,k;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
int temp=0;
for(k=0;k<4;k++)
{
temp=(temp+(a.data[i][k]*b.data[k][j])%m)%m;
}
ans.data[i][j]=temp;
}
}
return ans;
}
int matpow(struct matrix c,int n)
{
int j;
struct matrix res=I;
while(n>0)
{
if(n&1)
res=mul(res,c);
c=mul(c,c);
n=n/2;
}
int ans=0;
for(j=0;j<4;j++) //对第一行求和
ans=(ans+res.data[0][j])%m;
return ans;
}
在这室外温度40°C的天气里,能写这么一道题学些知识还是很有收获的啊。