第一种:斐波那契数列:
斐波那契数列的通项公式为:
f[i]=f[i-1]+f[i-2]
这种数列也是很经典的.
代码实现大致如下:
inline void work(){ f[1]=0; f[2]=1; for (int i=3;i<=n;i++) f[i]=f[i-1]+f[i-2]; }
这种数列还可以推出另一种通项公式的题:
f[i]=f[i-1]+f[i-2]+f[i-3]+...+f[i-m].
我们假设f[1],f[2],...,f[m]都是已知的.
这种题型的暴力形式可以直接这样:
inline void work(){ for (int i=m+1;i<=n;i++) for (int j=2;j<=m;j++) f[i]+=f[i-j+1]; }
当然我们可以用前缀和来优化,用F[i]表示f[1]+f[2]+...+f[i].
那么代码如下:
inline void work(){ for (int i=1;i<=m;i++) F[i]=f[i]+F[i-1]; for (int i=m+1;i<=n;i++) F[i]=2*F[i-1]-F[i-m-1]; }
若要对于mod取模,则可以这样写:
inline void work(){ for (int i=1;i<=m;i++) F[i]=(f[i]+F[i-1])%mod; for (int i=m+1;i<=n;i++) F[i]=(2*F[i-1]+mod-F[i-m-1])%mod; }
那么还有一种优化方案:矩阵乘法加速快速幂.
这种优化算法本人已有另一篇博客介绍,这里就不提了.
那么另一种经典递推:卡特兰数列.
令h(0)=1,h(1)=1.
通项公式1:
h(i)=h(0)*h(i-1)+h(1)*h(i-2)+...+h(j)*h(i-j-1)+...+h(i-1)*h(0).
代码实现:
inline void work(){ f[0]=f[1]=1; for (int i=2;i<=n;i++) for (int j=0;j<=i-1;j++) f[i]+=f[j]*f[i-j-1]; }
通项公式2:
h(i)=h(n-1)*(4*n-1)/(n+1)
代码实现(递归形式):
void h(int n){ if (n==1) return 1; else if (n==0) return 1; else return h(n-1)*(4*n-2)/(n+1); }
非递归形式:
inline void work(){ f[1]=f[0]=1; for (int i=2;i<=n;i++) f[i]=f[i-1]*(4*i-2)/(n+1); }
若要取余,由于除法取余涉及到了乘法逆元,我们一般就直接写通项公式1.
所以卡特兰数的应用主要是组合数学,例如出栈序列统计等.