Solution -「国家集训队」「洛谷 P4451」整数的 lqp 拆分

(mathcal{Description})

  Link.

  求

[sum_{m>0\a_{1..m}>0\a_1+cdots+a_m=n}prod_{i=1}^mf_{a_i} ]

  其中 (f_i) 为 Fibonacci 数列第 (i) 项((f_0=0,f_1=1)),答案对 (10^9+7) 取模。

  (nle10^{10^4})

(mathcal{Solution})

  记 (F(x))({f}) 的 OGF,首先来推导 (F(x))。根据定义 (f_{n+2}=f_{n+1}+f_n),可以发现经过适当位移,(F(x)) 能推出其自身而解出表达式。具体地:

[egin{aligned} &~~~~~~~~~~~xF(x)+F(x)=frac{1}xF(x)-1\ &Rightarrow~~~~(x+1-frac{1}x)F(x)=-1\ &Rightarrow~~~~F(x)=frac{x}{1-x-x^2} end{aligned} ]

  令 (n) 的答案为 (g_n)(g_0=1)。简单 DP 得出递推式:

[g_n=sum_{i=1}^nf_ig_{n-i} ]

  显然的卷积关系。令 ({g}) 的 OGF 为 (G(x)),则:

[egin{aligned} G(x)&=1+G(x)F(x)\ &=frac{1}{1-F(x)}\ &=frac{1-x-x^2}{1-2x-x^2} end{aligned} ]

  提出一些常数:

[Rightarrow~~~~G(x)=1-frac{x}{x^2+2x-1} ]

  我们想求 (g_n),即 ([x^n]G(x)),就得把上式最后一项分式结构配凑成等比数列求和的形式。首先暴力因式分解 (x^2+2x-1),用求根公式求出其两根:

[x_{1,2}=frac{-2pm2sqrt{2}}{2}=-1pmsqrt2 ]

  所以 (x^2+2x-1=(x-x_1)(x-x_2))。代入 (G(x)) 的表达式:

[egin{aligned} G(x)&=1-frac{x}{(x-x_1)(x-x_2)}\ &=1-frac{x}{x_1-x_2}left(frac{1}{x-x_1}-frac{1}{x-x_2} ight)\ &=1-frac{x}{x_1-x_2}left(frac{1}{x_2}sum_{i=0}^{+infty}frac{x^i}{x_2^i}-frac{1}{x_1}sum_{i=0}^{+infty}frac{x^i}{x_1^i} ight)\ &=1-frac{1}{x_1-x_2}sum_{i=1}^{+infty}(x_2^{-i}-x_1^{-i})x^i end{aligned} ]

  拆得清清楚楚啦,答案:

[[x^n]G(x)=(x_2-x_1)^{-1}(x_2^{-n}-x_1^{-n}) ]

  代入 (x_{1,2})

[[x^n]G(x)=-frac{sqrt2}4[(1-sqrt2)^n-(1+sqrt2)^n] ]

  最后 (sqrt2equiv 59713600equiv 940286407pmod{10^9+7}),所以可以 (mathcal O(log p+log n))(p) 是素模数)直接算出来。

(mathcal{Code})

/* Clearink */

#include <cstdio>

const int INV4 = 250000002, S2 = 59713600, MOD = 1e9 + 7;

inline int rmod () {
	int x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) {
		x = ( x * 10ll + ( s ^ '0' ) ) % ( MOD - 1 );
	}
	return x;
}

inline int mul ( const long long a, const int b ) { return a * b % MOD; }
inline int sub ( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int mpow ( int a, int b ) {
	int ret = 1;
	for ( ; b; a = mul ( a, a ), b >>= 1 ) ret = mul ( ret, b & 1 ? a : 1 );
	return ret;
}

int main () {
	int n = rmod ();
	printf ( "%d
", sub ( 0, mul ( mul ( S2, INV4 ),
		sub ( mpow ( sub ( 1, S2 ), n ), mpow ( add ( 1, S2 ), n ) ) ) ) );
	return 0;
}

原文地址:https://www.cnblogs.com/rainybunny/p/14253326.html