题解 P4451 【[国家集训队]整数的lqp拆分】
题意
题解
小清新生成函数。
记斐波那契数列的第\(i\)项为\(fib_i\),那么有:\(fib_0=0,fib_1=1,fib_n=fib_{n-1}+fib_{n-2}\)
令\(F(x)=\sum_{i=0}^{+\infty}fib_ix^i\),即斐波那契的生成函数,那么显然有:
\((2)\)式加\((3)\)式,由于\(fib_i+fib_{i+1}=fib_{i+2}\),可以得到:
与\((1)\)式对比一下,有:
设\(n\)的答案为\(g_n\),递推式应该比较容易。就是枚举最后的一个数字,在原来的基础上乘上这个数的斐波那契值,在累加答案,最后的式子应该就是:
特别地,我们令\(g_0=1\)
设\(g\)的生成函数为\(G\),即\(G(x)=\sum_{i=0}^{+\infty}g_ix^i\),那么对其进行展开:
不难发现,\(\sum_{n=1}^{+\infty}(\sum_{i=1}^ng_ifib_{n-i})x^n=F(x)\times G(x)\),因此:
此时只需要展开\(-\frac{x}{x^2+2x-1}\)即可。
我们知道,\(\frac{1}{1-cx^k}=\sum_{i=0}^{+\infty}(cx)^{ik}\),因此我们希望上式可以用这样的方式展开。
我们只需要解出\(x^2+2x-1=0\)的两根\(x_1,x_2\),\(x_{1,2}=-1±\sqrt{2}\),那么就有:
把常数项化为\(1\)
那么第\(n\)项的系数为\(g(n)=\dfrac{1}{x2-x1}\times(\dfrac{1}{x_2^n}-\dfrac{1}{x_1^n})\)
代入得到:\(g(n)=\dfrac{\sqrt{2}}{4}[(1+\sqrt{2})^n-(1-\sqrt{2})^n]\)
\(\sqrt2\)在模\(1000000007\)时等于\(59713600\)或\(940286407\)。
但是由于\(n\)的值很大,根据费马小定理,对\(mod-1\)取模即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<const int mod>
struct modint{
ll x;
modint(ll o=0){x=o;}
modint &operator = (ll o){return x=o,*this;}
modint &operator +=(modint o){return x=x+o.x>=mod?x+o.x-mod:x+o.x,*this;}
modint &operator -=(modint o){return x=x-o.x<0?x-o.x+mod:x-o.x,*this;}
modint &operator *=(modint o){return x=1ll*x*o.x%mod,*this;}
modint &operator ^=(ll b){
b%=(mod-1);
modint a=*this,c=1;
for(;b;b>>=1,a*=a)if(b&1)c*=a;
return x=c.x,*this;
}
modint &operator /=(modint o){return *this *=o^=mod-2;}
modint &operator +=(ll o){return x=x+o>=mod?x+o-mod:x+o,*this;}
modint &operator -=(ll o){return x=x-o<0?x-o+mod:x-o,*this;}
modint &operator *=(ll o){return x=1ll*x*o%mod,*this;}
modint &operator /=(ll o){return *this *= ((modint(o))^=mod-2);}
template<class I>friend modint operator +(modint a,I b){return a+=b;}
template<class I>friend modint operator -(modint a,I b){return a-=b;}
template<class I>friend modint operator *(modint a,I b){return a*=b;}
template<class I>friend modint operator /(modint a,I b){return a/=b;}
friend modint operator ^(modint a,ll b){return a^=b;}
friend bool operator ==(modint a,ll b){return a.x==b;}
friend bool operator !=(modint a,ll b){return a.x!=b;}
bool operator ! () {return !x;}
modint operator - () {return x?mod-x:0;}
void read(){
string s;cin>>s;x=0;
for(int i=0;i<s.length();i++)
*this*=10,*this+=s[i]-'0';
}void write(){
cout<<x;
}
};
modint<1000000006>n;
modint<1000000007>ans,sqrt2=59713600;
signed main(){
n.read();
ans=sqrt2/4*(((sqrt2+1)^n.x)-((-sqrt2+1)^n.x));ans.write();
return 0;
}