洛谷 P1487 失落的成绩单
传送门:洛谷 P1487 失落的成绩单
题目描述:
数列 \(a\) 满足
给出:首项 \(A_1\)、末项 \(A_n\)、\(d\)、\(m\),求\(A_m\)
算法分析:
矩阵快速幂?还没学,所以我们就用数(mo)学(fa)来解决这道题。
预备知识:特征方程
我们以这个式子为例—— \(f_i=f_{i-1}+6f_{i-2}\)
首先我们来看两个数集
\(A=\{x\mid x=(-2)^k,k\in\mathbb{N^*}\}\ ,\ B=\{x\mid x=3^k,k\in\mathbb{N^*}\}\)
那么,我们可以列出 \(A\) 的前几项:\(-2,4,-8,16,...\),\(B\) 的前几项:\(3,9,27,81,...\)
将 \(A\) 代入递推式,神奇的发现——
\(f_1=-2\)
\(f_2=4\)
\(f_3=4+6\times(-2)=-8\)
\(f_4=-8+6\times4=16\)
\(......\)
\(A\) 中的数都满足上述的递推式,同样的,\(B\) 也满足。
很明显,\(f_i=(-2)^k\) 和 \(f_i=3^k\) 都是上述递推式的通项公式
下面我们来看两个引理——
1、若 \(f_i=a^i\) 是某一递推式的通项公式,那么,\(f_i=\lambda a^i\) 同样满足递推式(两边同乘上系数即可)
2、若 \(f_i=a^i\) 和 \(f_i=b^i\) 都满足递推式,那么,\(f_i=\alpha\times a^i+\beta\times b^i\) 同样满足(两式乘上系数相加即可)
接下来,我们来看一个经典的例子——斐波拉契数列 \(f_i=f_{i-1}+f_{i-2}\)
现在我们不能像刚才那个式子“观察”出一个通解了,那么就需要我们自己进行构造(自己动手,丰衣足食)
现在我们设存在一组等比数列满足这个递推式(不是等比怎么约分啊),其公比为 \(q\) ,那么我们看一下这个式子——
这就是斐波拉契数列的特征方程
把它解出来,可以得到—— \(q_1=\frac{\sqrt5+1}{2},q_2=\frac{-\sqrt5+1}{2}\)
那么,我们就知道了——公比为\(\frac{\pm\sqrt5+1}{2}\)的等比数列满足斐波拉契数列
那么,我们又知道了数列的前两项:\(f_1=f_2=1\)
我们设 \(f_i=\alpha\times(\frac{\sqrt5+1}{2})^i+\beta\times(\frac{-\sqrt5+1}{2})^i\),代入\(f_1,f_2\)
则——
得 \(\alpha=\frac{\sqrt5}{5},\beta=-\frac{\sqrt5}{5}\),这样,我们就求出了通项公式
回到之前的递推数列——\(f_i=f_{i-1}+6f_{i-2}\),怎么得出其通解的?
其实很简单。我们设等比数列公比为 \(q\),就可以得到特征方程—— \(q^2-q-6=0 \Rightarrow q_1=-2,q_2=3\)
进入正题,首先来膜改一下式子:
这是 \(A\) 的递推式,我们将 \(i\) 减 \(1\):
现在我们得出了答案 —— \(A_{i}=-2A_{i-1}+A_{i-2}+2d\)
那么我们先将 \(2d\) 放在一边,设数列 \(a\) 满足 \(a_{i}=-2a_{i-1}+a_{i-2}\)
设此数列公比为 \(q\),现在代入——
这就是上述递推式的特征方程
现在解一下这个方程,可以得到—— \(q_1=-\sqrt{2}-1,q_2=\sqrt{2}-1\)
那么我们就可以得到这个数列的通项公式——
其中 \(i\leq n\),并且
将上面的方程解出来,我们可以得到——
代入通项公式并整理——
设\(f(x)=(\sqrt2-1)^x-(-1)^x(\sqrt2+1)^x\),可得
好了,现在是最后一个问题——还有\(d\)呢!
其实很容(kun)易(nan),观察递推式—— \(A_i=-2A_{i-1}+A_{i-2}+2d\)
我们设 \(A_i=a_i+p\times d\),代入——
我们又有 \(a_{i}=-2a_{i-1}+a_{i-2}\),那么两边约去,可得——
故 \(A_i=a_i+d\)
那么,根据题意,我们来膜改一下式子——
这样,我们就得到了数列的通项公式,代码就很好写了(没用龟(kuai)速幂,数据太弱QwQ)
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double p=sqrt(2)-1;
int n,m; double d,a1,an;
double c(int op) {return (op&1)?-1:1;}
double f(int x) {return pow(p,x)-c(x)*pow(p+2,x);}
int main()
{
scanf("%d%d%lf%lf%lf",&n,&m,&d,&a1,&an);
if(m==0) printf("0.000");
else printf("%.3lf",((an-d)*f(m-1)+c(m-1)*(a1-d)*f(n-m))/f(n-1)+d);
return 0;
}