@codechef - JADUGAR2@ Chef and Same Old Recurrence 2


@description@

定义 dp 序列:

\[dp(1) = K\\ dp(n) = A\times dp(n-1) + B\times \sum_{i=1}^{n-1}dp(i)\times dp(n-i)\]

Q 次询问,每次询问给出 L, R,求 \(\sum_{i=L}^{R}dp(i)^2\),对 10^9 + 7 取模。

原题戳我查看owo

@solution@

考虑写出生成函数 \(F(x) = \sum_{i=0}dp(i)x^i\),得到:

\[F(x) = Ax\times F(x) + B\times F^2(x) + Kx \]

解方程得到 \(F(x) = \frac{(1-Ax)\pm\sqrt{(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)\times 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)\times dp(n-1) - 2(A + 2BK)n\times dp(n) + (n+1)\times 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\n", sub(f[R], f[L-1]));
	}
}

@details@

查了很久都没有查到卡特兰数的递推公式的生成函数证法(甚至翻到了wiki上去都没有。。。)。

一看题解,woc 还有求导这种操作。

早知道就不花几个晚上思考了。。。直接翻题解不挺好的。。。

posted @ 2020-01-02 12:53  Tiw_Air_OAO  阅读(208)  评论(0编辑  收藏  举报