Step 0:食用前准备
- 知识:带数列的通项公式
- 只需要具备初一基本代数知识。
- 代码很短,数学题,准备好足够的耐心看完推导过程。
Step 1:题意简化
有一个数列 g g g ,满足:
- g 0 = x g_0=x g0=x , x x x 为给定数;
- g i + 1 = A × g i + B g_{i+1}=A\times g_i+B gi+1=A×gi+B , A A A 和 B B B 为给定数。
求 g n g_n gn 的值,并对 1 0 9 + 7 10^9+7 109+7 取模。
Step 2:分析
g 0 = x g_0=x g0=x , g 1 = A × g 0 + B g_1=A\times g_0+B g1=A×g0+B , g 2 = A × g 1 + B g_2=A\times g_1+B g2=A×g1+B ,… ,感觉像套娃的样子。
发现每次都会先乘上一个 A A A ,那么最后的结果猜测是与 A n A^n An 有关的东西。
那也不能让它一直套下去,得想办法求出 g g g 的通项公式才行。
今天介绍一种求数列通项公式的方法:待定系数法求数列通项公式。
强烈推荐百度搜索“待定系数法求数列的通项公式”。
Step 3:计算
Part 1
设: g n + 1 + k = A ( g n + k ) g_{n+1}+k=A(g_n+k) gn+1+k=A(gn+k) , n ∈ N n\in N n∈N . // n ∈ N n\in N n∈N 指的是 n n n 属于自然数。
把上述式子拆开、移项、合并同类项得: g n + 1 = A × g n + ( A − 1 ) k g_{n+1}=A\times g_n+(A-1)k gn+1=A×gn+(A−1)k .
又依题有: g i + 1 = A × g i + B g_{i+1}=A\times g_i+B gi+1=A×gi+B ,两式对比得: B = ( A − 1 ) k B=(A-1)k B=(A−1)k ,
除过去求出 k k k 得: k = B A − 1 k=\frac{B}{A-1} k=A−1B . //为了让思路更加清晰,这里先不考虑 A − 1 = 0 A-1=0 A−1=0 的情况,后面会补充说明。
在一开始我们设了一个式子: g n + 1 + k = A ( g n + k ) g_{n+1}+k=A(g_n+k) gn+1+k=A(gn+k)
那么把算出来的 k k k 代进去得: g n + 1 + B A − 1 = A ( g n + B A − 1 ) g_{n+1}+\frac{B}{A-1}=A(g_n+\frac{B}{A-1}) gn+1+A−1B=A(gn+A−1B)
哇!是不是有点像等比数列?
Part 2
我们设 h n = g n + B A − 1 h_n=g_n+\frac{B}{A-1} hn=gn+A−1B ,再对比上面最新的式子, h h h 恰好就是公比为 A A A 的等比数列!
即 h n + 1 = A × h n h_{n+1}=A\times h_n hn+1=A×hn
由于 h 0 = g 0 + B A − 1 h_0=g_0+\frac{B}{A-1} h0=g0+A−1B ,那么 h n = A n × h 0 = A n × ( g 0 + B A − 1 ) h_n=A^n\times h_0=A^n\times (g_0+\frac{B}{A-1}) hn=An×h0=An×(g0+A−1B)
所以 h h h 的通项公式就有了,但是我们的终极目标是求 g g g 的通项公式,那怎么办?
怎么办呢?Part 2的最开始设了 h n = g n + B A − 1 h_n=g_n+\frac{B}{A-1} hn=gn+A−1B ,可以得出:
g n = h n − B A − 1 = A n × ( g 0 + B A − 1 ) − B A − 1 g_n=h_n-\frac{B}{A-1}=A^n\times (g_0+\frac{B}{A-1})-\frac{B}{A-1} gn=hn−A−1B=An×(g0+A−1B)−A−1B
再整理一下上面的式子,题目将 g 0 g_0 g0 输入为 x x x ,顺便替换掉: g n = A n × g 0 + ( A n − 1 ) × B A − 1 = A n × x + ( A n − 1 ) × B A − 1 g_n=A^n\times g_0+(A^n-1)\times \frac{B}{A-1}=A^n\times x+(A^n-1)\times \frac{B}{A-1} gn=An×g0+(An−1)×A−1B=An×x+(An−1)×A−1B
好了, g n g_n gn 的通项公式就解决了,我们用了 A A A , B B B , x x x ,来表示出了 g n g_n gn 。
Part 3
现在还有一个小问题:刚才把 g n g_n gn 求出来了,那这个式子里 A − 1 A-1 A−1 分母等于 0 0 0 怎么办?也就是 A = 1 A=1 A=1 怎么办?
那太好办了,如果 A = 1 A=1 A=1 ,也就是说 g i + 1 = g i + B g_{i+1}=g_i+B gi+1=gi+B , g g g 为等差数列。
这个时候 g n = g 0 + n × B g_n=g_0+n\times B gn=g0+n×B 。
输入的时候特判一下就可以了。
if(a==1){
cout<<(x+n%mod*b%mod)%mod<<endl;
return 0;
}
Step 4:实现上的一些细节
式子求出来了,结果发现输入有亿点点大,而且这个式子是分式,也就是还要算除法。
输入较大,用上快速幂,记得及时取模。
在计算的过程中需要除以 A − 1 A-1 A−1 ,这个时候除以 A − 1 A-1 A−1 就相当于乘 A − 1 A-1 A−1 模 m o d mod mod 意义下的逆元。
由于题目里要求取模的 1 0 9 + 7 10^9+7 109+7 是质数,所以这份代码是根据费马小定理求的逆元,不明白的可以自行学习一下~~(具体方法:百度搜索“费马小定理求逆元”)~~。
long long inv=pw(a-1,mod-2); //pw是快速幂的函数
Step 5:完整代码
#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
unsigned long long a,b,n,x;//开一下long long
long long pw(long long a,long long b)
{
long long ans=1,base=a;
while(b!=0){
if(b&1!=0) ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return ans%mod;
}
signed main()
{
cin>>a>>b>>n>>x;
if(a==1){
cout<<(x+n%mod*b%mod)%mod<<endl;
return 0;
}
long long inv=pw(a-1,mod-2);//求a-1的逆元
long long power=pw(a,n);//求a的n次方
long long ans=((power-1)*inv%mod*b%mod+x%mod*power%mod)%mod;//根据刚才的式子代入即可
cout<<ans<<endl;
return 0;
}
ps:数学不好,有问题尽管指正。