2019.03.29【洛谷P4451】【BZOJ2173】整数的lqp拆分(生成函数)

洛谷传送门

BZOJ传送门


解析:

g i g_i gi表示一个整数的lqp拆分的权值,其生成函数为 G ( x ) G(x) G(x) f i f_i fi表示第 i i i个斐波那契数,生成函数为 F ( x ) F(x) F(x)

g 0 = 0 , g 1 = 1 g_0=0,g_1=1 g0=0,g1=1

很显然我们可以发现:
g n = ∑ i = 1 n g i f n − i + f n G = G ∗ F + F g_n=\sum_{i=1}^{n}g_if_{n-i}+f_n\\ G=G*F+F gn=i=1ngifni+fnG=GF+F

也就是 G = F 1 − F G=\frac{F}{1-F} G=1FF

我们知道斐波那契数列的生成函数闭形式是 F = 1 1 − x − x 2 F=\frac{1}{1-x-x^2} F=1xx21,代到上面去可以得到 G = x 1 − 2 x − x 2 G=\frac{x}{1-2x-x^2} G=12xx2x

也就是 G = 2 x G + x 2 G + x G=2xG+x^2G+x G=2xG+x2G+x,最后面那个 1 1 1是对于 g 1 g_1 g1的,不用管,对于 i > 1 i>1 i>1,我们得到递推式 g i = 2 g i − 1 + g i − 2 g_i=2g_{i-1}+g_{i-2} gi=2gi1+gi2

推到这里已经可以过这道题了,那么我们把 n n n放到 1 e 18 1e18 1e18如何?

显然我们继续推是可以得到通项公式的。

拆掉分母: x 1 − 2 x − x 2 = x ( 1 − ( 1 − 2 ) x ) ( 1 − ( 1 + 2 ) x ) \frac{x}{1-2x-x^2}=\frac{x}{(1- (1-\sqrt 2 )x)(1-(1+\sqrt 2 )x)} 12xx2x=(1(12 )x)(1(1+2 )x)x

待定系数,设 G = a ( 1 − 2 ) x + b 1 − ( 1 + 2 ) x G=\frac{a}{(1-\sqrt 2 )x}+\frac{b}{1-(1+\sqrt 2 )x} G=(12 )xa+1(1+2 )xb

恒等变形解得 a = − 2 4 , b = 2 4 a=-\frac{\sqrt 2}{4},b=\frac{\sqrt 2}{4} a=42 ,b=42

随手写一个二次剩余,或者直接暴力 1 e 9 + 7 1e9+7 1e9+7,也不慢, 10 s 10s 10s内随便跑出来,我们得到 5971360 0 2 ≡ 2 ( m o d 1 e 9 + 7 ) 59713600^2\equiv 2\pmod{1e9+7} 5971360022(mod1e9+7)

通项公式: g n = 2 4 ( ( 1 + 2 ) n − ( 1 − 2 ) n ) g_n=\frac{\sqrt 2}{4}((1+\sqrt 2)^n-(1-\sqrt 2)^n) gn=42 ((1+2 )n(12 )n)


代码:(递推)

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
int n;
int g[1000006];
signed main(){
	std::cin>>n;
	g[1]=1;
	for(int re i=2;i<=n;++i)g[i]=add(add(g[i-1],g[i-1]),g[i-2]);
	std::cout<<g[n]<<"\n";
	return 0;
}

代码:(通项)

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int quickpow(int a,int b,int res=1){
	while(b){
		if(b&1)res=mul(res,a);
		a=mul(a,a);
		b>>=1;
	}
	return res;
}

cs int sqr2=59713600,inv2=(mod+1)>>1;

int n;
signed main(){
	std::cin>>n;
	std::cout<<mul(mul(sqr2,mul(inv2,inv2)),dec(quickpow(add(1,sqr2),n),quickpow(dec(1,sqr2),n)));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值