@codechef - JADUGAR2@ Chef and Same Old Recurrence 2
Posted tiw-air-oao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@codechef - JADUGAR2@ Chef and Same Old Recurrence 2相关的知识,希望对你有一定的参考价值。
@description@
定义 dp 序列:
[dp(1) = Kdp(n) = A imes dp(n-1) + B imes sum_{i=1}^{n-1}dp(i) imes dp(n-i)]
Q 次询问,每次询问给出 L, R,求 (sum_{i=L}^{R}dp(i)^2),对 10^9 + 7 取模。
@solution@
考虑写出生成函数 (F(x) = sum_{i=0}dp(i)x^i),得到:
[F(x) = Ax imes F(x) + B imes F^2(x) + Kx]
解方程得到 (F(x) = frac{(1-Ax)pmsqrt{(1-Ax)^2 - 4KBx}}{2B})。因为 F(x) 常数项为 0,舍弃一个根。有:
[F(x) = frac{(1-Ax)-sqrt{(1-Ax)^2 - 4KBx}}{2B}]
尝试展开得到通项,发现展不开。
注意到当 A = 0 时就是个类似于卡特兰数的数列了,而卡特兰数众所周知有一个递推式子 (f_n = frac{4n-2}{n+1}f_{n-1})。
考虑给题目的数列找一个递推式子。首先我们考虑一下怎么通过生成函数得到卡特兰数的递推式子。
-----手动分割线-----
记 (G(x) = sum_{i=0}f_ix^i),即卡特兰数的生成函数,众所周知 (G(x) = frac{1 - sqrt{1-4x}}{2x})。
考虑对 (G(x)) 求导得到 (G'(x) = sum_{i=0}(i+1) imes f_{i+1}x^i),根据求导法则有 (G'(x) = frac{(2x-1)sqrt{1-4x}-4x+1}{8x^3 - 2x^2})。
因为 (G(x) = frac{1 - sqrt{1-4x}}{2x}),可以得到 (sqrt{1-4x} = 1 - 2xG(x)),直接代入上式得到 (G'(x) = frac{-2xG(x)+G(x)+1}{4x^2-x})。
稍微变形可得 ((4x^2-x)G'(x) + (2x-1)G(x) = 1)。
对比等式两边第 n 项的系数(假设 n ≠ 0),有 (4(n-1)f_{n-1} - nf_{n} + 2f_{n-1} - f_{n} = 0)。然后就可以得到 (f_n = frac{4n-2}{n+1}f_{n-1}) 的结果。
-----手动分割线-----
该题也是类似的处理:求出 (F'(x)) 的表达式,用 (F(x)) 表示出根号项并代入 (F'(x)),最后可以得到这样一个结果(过程我就不给了,类似于上面的推导主要是太太太长了不想给):
[(A^2x^2 - (4BK + 2A)x + 1)F'(x) + ((A + 2BK) - A^2x)F(x) = AKx + K]
然后依然是对比第 n 项系数(n > 1),得到 (A^2(n-1) imes dp(n-1) - 2(A + 2BK)n imes dp(n) + (n+1) imes dp(n+1) + (A + 2BK)dp(n) - A^2dp(n-1) = 0)
于是得到递推式 ((n+1)dp(n+1) = (2n - 1)(A + 2BK)dp(n) - A^2(n-2)dp(n-1))。
即 (dp(n) = frac{(2n - 3)(A + 2BK)dp(n) - A^2(n-3)dp(n-2)}{n})。
然后就没了。直接 O(N) 预处理。
@accepted code@
#include <cstdio>
const int MAXN = 10000000;
const int MOD = int(1E9) + 7;
int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
int sub(int a, int b) {return a - b < 0 ? a - b + MOD : a - b;}
int mul(int a, int b) {return 1LL*a*b%MOD;}
int N, K, A, B, Q;
int f[MAXN + 5], inv[MAXN + 5];
void init() {
inv[1] = 1;
for(int i=2;i<=N;i++)
inv[i] = (MOD - 1LL*(MOD/i)*inv[MOD%i]%MOD);
int p = add(A,mul(2*K,B)), q = mul(A,A);
f[1] = K, f[2] = mul(K,add(A,mul(B,K)));
for(int i=3;i<=N;i++)
f[i] = mul(inv[i],sub(mul(mul(p,2*i-3),f[i-1]),mul(mul(q,i-3),f[i-2])));
for(int i=1;i<=N;i++) f[i] = add(f[i-1],mul(f[i],f[i]));
}
int main() {
scanf("%d%d%d%d", &N, &K, &A, &B), init();
scanf("%d", &Q);
for(int i=1;i<=Q;i++) {
int L, R; scanf("%d%d", &L, &R);
printf("%d
", sub(f[R], f[L-1]));
}
}
@details@
查了很久都没有查到卡特兰数的递推公式的生成函数证法(甚至翻到了wiki上去都没有。。。)。
一看题解,woc 还有求导这种操作。
早知道就不花几个晚上思考了。。。直接翻题解不挺好的。。。
以上是关于@codechef - JADUGAR2@ Chef and Same Old Recurrence 2的主要内容,如果未能解决你的问题,请参考以下文章