Loading

P4451 [国家集训队]整数的lqp拆分

P4451 [国家集训队]整数的lqp拆分

之前看过cmd的blog,还算有点生成函数基础了,所以这题还能动。

\(F(x)=f_ix^i\)\(f_i\) 表示斐波那契数列第 \(i\) 项(\(f_0=0,f_1=1,f_i=f_{i-1}+f_{i-2}\)) ,那么答案就是

\[G(x)=\sum_{k=0} F^k(x)=\dfrac{1}{1-F(x)} \]

这个应该很好理解,枚举用了 \(k\) 个数就可以得到上式。

斐波那契的生成函数可以用如下方法计算

\[F(x)=f_0+f_1x+f_2x^2+f_3x^3+f_4x^4+\cdots\\ xF(x)=f_0x+f_1x^2+f_2x^3+f_3x^4+\cdots\\ x^2F(x)=f_0x^2+f_1x^3+f_2x^4+\cdots\\ \]

结合 \(f_i=f_{i-1}+f_{i-2}\) 得:

\[F(x)-f_0-f_1x=xF(x)-f_0x+x^2F(x)\\ F(x)-x=xF(x)+x^2F(x)\\ (x^2+x-1)F(x)+x=0\\ F(x)=\dfrac{x}{1-x-x^2} \]

带到最开头那个式子得到答案的生成函数

\[G(x)=\dfrac{1}{1-F(x)}\\ =\dfrac{1}{1-\dfrac{x}{1-x-x^2}}\\ =\dfrac{1-x-x^2}{1-x-x^2-x}\\ =\dfrac{1-x-x^2}{1-2x-x^2}\\ =1-\dfrac{x}{1-2x-x^2} \]

这个封闭告诉不了我们什么东西,要化简。(跟着cmd的方法学的)

尝试因式分解分母尝试化成一堆 \(\dfrac{1}{1-qx^k}\) 相加的形式。

\(1-2x-x^2=0\) 的两根为 \(x_1,x_2\)\(x_1=-1-\sqrt{2},x_2=-1+\sqrt{2}\)

\[\dfrac{1}{x-x_1}-\dfrac{1}{x-x_2}=\dfrac{x_1-x_2}{(x-x_1)(x-x_2)} \]

\[G(x)=1-\dfrac{x}{(x-x_1)(x-x_2)}\\ =1-\dfrac{x}{x_1-x_2}(\dfrac{1}{x-x_1}-\dfrac{1}{x-x_2})\\ =1-\dfrac{x}{x_1-x_2}(\dfrac{1}{x_2}\dfrac{1}{1-\frac{1}{x_2}}+\dfrac{1}{x_1}\dfrac{1}{1-\frac{1}{x_1}})\\ =1-\dfrac{1}{x_1-x_2}(\sum_{i=0}\dfrac{x^{i+1}}{x_2^{i+1}}-\sum_{i=0}\dfrac{x_{i+1}}{x_1^{i+1}}) \]

提取第 \(n\) 项系数

\[[x^n]G(x)=\dfrac{1}{x_2-x_1}(\dfrac{1}{x_2^{n}}-\dfrac{1}{x_1^n})\\ =\dfrac{1}{2\sqrt{2}}((1+\sqrt{2})^{n}-(1-\sqrt{2})^{n}) \]

写个程序暴力 for 一遍,1 min 内绝对能跑出 \(\sqrt{2}\bmod 10^9+7\) ,然后快速幂算就好了。

实测 2.47s ,本地可以优化乱开,都开上会快很多。。。

你可能会好奇那个 \(1\) 哪里去了。我tm都做了三道生成函数了还在想这个问题,那个 \(1\) 是加在 \([x^0]\) 上的。所以我手动带入 \(n=3\) 发现那个式子已经等于 \(5\) 了人都傻了(样例),后来才反应过来。

读入时候根据费马小定理 \(n\bmod (mod-1)\)

艹这种题我能挂3发

两行求 \(\sqrt{2}\bmod 10^9+7\)

#define mod 1000000007
signed main(){for(int i=1;;++i)if(1ll*i*i%mod==2){cout<<i<<'\n';return 0;}}

然后偷懒 #define int long long 了。

#define int long long
#define mod 1000000007
const int is2=59713600;
inline int modread(const int&p){
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x*10ll+ch-'0')%p,ch=getchar();
	return x;
}
inline int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
signed main(){
	int n=modread(mod-1),ans=(qpow(1+is2,n)-qpow(mod+1-is2,n)+mod)%mod*qpow(is2*2%mod,mod-2)%mod;
	cout<<ans<<'\n';
}
posted @ 2021-01-01 23:12  zzctommy  阅读(100)  评论(0编辑  收藏  举报