欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-08 19:06:02
...

洛谷传送门

BZOJ传送门


解析:

gig_i表示一个整数的lqp拆分的权值,其生成函数为G(x)G(x)fif_i表示第ii个斐波那契数,生成函数为F(x)F(x)

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

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

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

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

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

推到这里已经可以过这道题了,那么我们把nn放到1e181e18如何?

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

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

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

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

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

通项公式:gn=24((1+2)n(12)n)g_n=\frac{\sqrt 2}{4}((1+\sqrt 2)^n-(1-\sqrt 2)^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;
}