特征根方程-求解递推数列通项的工具
特征方程,实际上就是为研究相应的数学对象而引入的一些等式,它因数学对象不同而不同,包括数列特征方程,矩阵特征方程,微分方程特征方程,积分方程特征方程等等。
特征根方程是数学竞赛中常用的一种解题技巧,可以处理形如
这样的数列通项。
一个这样的递推数列的特征根方程就是
有没有很熟悉的感觉?
我们令
正是我们最熟悉的
先放结论
我们定义特征根方程的根为特征根。
特征根与数列通项的关系
① 有两个不等特征根,设为
② 有两个相等特征根,设为
那么
根据韦达定理,原特征根方程的两根
那么这里的
根据韦达定理的逆定理,这里的
我们同样分刚才的两种情况考虑。
①s=r
根据一元二次方程的求根公式,△
解得
我们设
我们代入原来的递推式中。那么
看出什么了吗?
令数列
那么
等式右边为常数,并且我们观察到等式左边两项结构相同,均为
根据等差数列性质:
因为两根相等,根据韦达定理,
那么,
我们设
代回原式,
② s≠r
其实和刚才类似。
根据韦达定理,我们可以求得
根据等比数列公式,
相减得
换元即得
证毕!
例题
求fibonacci数列的通项公式
特征方程为:
解得
则
∵
代入这两个值
解得
∴
怎么转换为代码?使用结构体存储一个数的
分数怎么办?
我们只需要除以2和10。由于原题答案要模
就可以愉快的打代码了!
是不是比什么矩阵乘法简单多了?(逃
#include<cstdio>
#include<cstring>
#define ll long long
ll mod=1000000007;
long long mo(ll x){
return ((x%mod)+mod)%mod;
}
struct num{
ll s5,z;//sqrt(5)项,整项
};
num mul(num x,num y)
{
num ans;
ans.z=mo(mo(x.z*y.z)+mo(5ll*x.s5)*y.s5);
ans.s5=mo(mo(x.s5*y.z)+mo(x.z*y.s5));
return ans;
}
num qpow(num x,ll y)
{
num ans;
ans.s5=0;ans.z=1;
while (y){
if (y&1) ans=mul(x,ans);
x=mul(x,x);
y>>=1;
}
return ans;
}
int main()
{
ll n;
scanf("%lld",&n);
n--;
num a,b,c,d,e,f;
a.s5=700000005;
c.z=a.z=b.z=b.s5=d.z=500000004;
d.s5=mo(-500000004);
c.s5=mo(-700000005);
e=mul(a,qpow(b,n));
f=mul(c,qpow(d,n));
printf("%lld\n",mo(e.z+f.z));
return 0;
}
完结撒花!
参考资料:数列通项特征根法的证明https://wenku.baidu.com/view/71b1a7bcf90f76c661371ab6.html
特别鸣谢数学竞赛大佬CYX提供了巨大的帮助!