博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CF717A Festival Organization(第一类斯特林数,斐波那契数列)
阅读量:5045 次
发布时间:2019-06-12

本文共 4371 字,大约阅读时间需要 14 分钟。

题目大意:求 $\sum\limits_{n=l}^{r}\dbinom{f_n}{k}\bmod 10^9+7$。其中 $f_n$ 是长度为 $n$ 的 $01$ 序列中,没有连续两个或超过两个 $0$ 的个数。

$1\le k\le 200,1\le l\le r\le 10^{18}$。


先考虑如何求 $f_n$。

令 $g[i][j]$ 表示长度为 $i$,结尾是 $j$ 的序列个数。

$$g[i][0]=g[i-1][1]$$

$$g[i][1]=g[i-1][0]+g[i-1][1]$$

将第一个式子代入第二个式子有 $g[i][1]=g[i-2][1]+g[i-1][1]$。

手玩发现 $g[1][1]=1,g[2][1]=2$。那么有 $g[i][1]=fib_{i+1}$。($fib$ 是斐波那契数列)

要求 $g[i][0]+g[i][1]=g[i-1][1]+g[i][1]=g[i+1][1]=fib_{i+2}$。

那么式子就是 $\sum\limits_{n=l+2}^{r+2}\dbinom{fib_n}{k}$。(为方便 $l+=2,r+=2$,下文假设是 $l$ 到 $r$)

$$\sum\limits_{n=l}^r\dbinom{fib_n}{k}$$

$$\dfrac{1}{k!}\sum\limits_{n=l}^rfib_n^{\underline{k}}$$

$$\dfrac{1}{k!}\sum\limits_{n=l}^r\sum\limits_{i=0}^k(-1)^{k-i}\begin{bmatrix}k\\i\end{bmatrix}fib_n^i$$

$$\dfrac{1}{k!}\sum\limits_{i=0}^k(-1)^{k-i}\begin{bmatrix}k\\i\end{bmatrix}\sum\limits_{n=l}^rfib_n^i$$

前面可以随便枚举,然而斐波那契 $k$ 次方前缀和这东西怎么搞?

这时就要用上大名鼎鼎的通项公式:(没记住的也可以现场用特征方程推)

$$fib_n=\dfrac{\sqrt{5}}{5}(\dfrac{1+\sqrt{5}}{2})^n-\dfrac{\sqrt{5}}{5}(\dfrac{1-\sqrt{5}}{2})^n$$

令 $a=\dfrac{\sqrt{5}}{5},b=-\dfrac{\sqrt{5}}{5},x=\dfrac{1+\sqrt{5}}{2},y=\dfrac{1-\sqrt{5}}{2}$,那么 $fib_n=ax^n+by^n$。

$$\dfrac{1}{k!}\sum\limits_{i=0}^k(-1)^{k-i}\begin{bmatrix}k\\i\end{bmatrix}\sum\limits_{n=l}^r(ax^n+by^n)^i$$

$$\dfrac{1}{k!}\sum\limits_{i=0}^k(-1)^{k-i}\begin{bmatrix}k\\i\end{bmatrix}\sum\limits_{n=l}^r\sum\limits_{j=0}^i\dbinom{i}{j}(ax^n)^j(by^n)^{i-j}$$

$$\dfrac{1}{k!}\sum\limits_{i=0}^k(-1)^{k-i}\begin{bmatrix}k\\i\end{bmatrix}\sum\limits_{n=l}^r\sum\limits_{j=0}^i\dbinom{i}{j}(a^jb^{i-j})(x^jy^{i-j})^n$$

$$\dfrac{1}{k!}\sum\limits_{i=0}^k(-1)^{k-i}\begin{bmatrix}k\\i\end{bmatrix}\sum\limits_{j=0}^i\dbinom{i}{j}(a^jb^{i-j})\sum\limits_{n=l}^r(x^jy^{i-j})^n$$

此时 $i$ 和 $j$ 可以 $O(k^2)$ 枚举,而 $n$ 那里是个等差数列,总复杂度 $O(k^2\log r)$。(可能要预处理出所有斯特林数和组合数才能做到这个复杂度)

但是有个严重的问题:$\sqrt{5}$ 在模 $10^9+7$ 意义下不存在。

那么就要用到一个骚操作:扩系。

令 $(a,b)=a+b\sqrt{5}$,那么上文中的四个常数 $a=(0,5^{-1}),b=(0,-5^{-1}),x=(2^{-1},2^{-1}),y=(2^{-1},-2^{-1})$。

那么进行加减乘除就简单了:

$$(a,b)\pm(c,d)=(a\pm c,b\pm d)$$

$$(a,b)\times(c,d)=(ac+5bd,ad+bc)$$

$$\dfrac{1}{(a,b)}=(\dfrac{a}{a^2-5b^2},\dfrac{-b}{a^2-5b^2})$$

因为式子没推错(只能这么想了啊),最后求出的一定是整数。

那么就做完了。

#include
using namespace std;typedef long long ll;const int maxn=222,mod=1000000007,inv2=500000004,inv5=400000003;#define FOR(i,a,b) for(int i=(a);i<=(b);i++)#define ROF(i,a,b) for(int i=(a);i>=(b);i--)#define MEM(x,v) memset(x,v,sizeof(x))inline ll read(){ char ch=getchar();ll x=0,f=0; while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x;}int k,fac[maxn],invfac[maxn],ans,S[maxn][maxn],C[maxn][maxn];ll l,r;inline int add(int x,int y){
return x+y
>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans;}struct comp{ int x,y; comp(const int xx=0,const int yy=0):x(xx),y(yy){} inline comp operator+(const comp &c)const{
return comp(add(x,c.x),add(y,c.y));} inline comp operator-(const comp &c)const{
return comp(sub(x,c.x),sub(y,c.y));} inline comp operator*(const comp &c)const{
return comp(add(mul(x,c.x),mul(5,mul(y,c.y))),add(mul(x,c.y),mul(y,c.x)));} inline comp inv()const{ comp ans(x,y?mod-y:0); int dn=qpow(sub(mul(x,x),mul(5,mul(y,y))),mod-2); return ans*dn; } inline comp operator/(const comp &c)const{
return *this*c.inv();} inline bool operator==(const comp &c)const{
return x==c.x && y==c.y;}}a(0,inv5),b(0,mod-inv5),x(inv2,inv2),y(inv2,mod-inv2);inline comp cqpow(comp a,ll b){ comp ans(1,0); for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a; return ans;}comp calc(comp x,ll l,ll r){ if(x==1) return (r-l+1)%mod; return (cqpow(x,r+1)-cqpow(x,l))/(x-1);}int main(){ k=read();l=read();r=read(); FOR(i,0,k) C[i][0]=C[i][i]=1; FOR(i,1,k) FOR(j,1,i-1) C[i][j]=add(C[i-1][j],C[i-1][j-1]); S[1][1]=1; FOR(i,2,k) FOR(j,1,i) S[i][j]=add(mul(i-1,S[i-1][j]),S[i-1][j-1]); fac[0]=1; FOR(i,1,k) fac[i]=mul(fac[i-1],i); invfac[k]=qpow(fac[k],mod-2); FOR(i,0,k){ int s=0; FOR(j,0,i){ comp tmp1=cqpow(a,j)*cqpow(b,i-j),tmp2=cqpow(x,j)*cqpow(y,i-j); s=add(s,mul(C[i][j],(tmp1*calc(tmp2,l+2,r+2)).x)); } s=mul(s,S[k][i]); if((k-i)&1) ans=sub(ans,s); else ans=add(ans,s); } printf("%d\n",mul(ans,invfac[k]));}
View Code

 

转载于:https://www.cnblogs.com/1000Suns/p/11030886.html

你可能感兴趣的文章
SQLServer 镜像功能完全实现
查看>>
Vue-详解设置路由导航的两种方法
查看>>
一个mysql主从复制的配置案例
查看>>
大数据学习系列(8)-- WordCount+Block+Split+Shuffle+Map+Reduce技术详解
查看>>
dvwa网络渗透测试环境的搭建
查看>>
Win8 安装VS2012 和 Sql Server失败问题
查看>>
过点(2,4)作一直线在第一象限与两轴围成三角形,问三角形面积的最小值?...
查看>>
java aes CBC的填充方式发现
查看>>
使用ionic cordova build android --release --prod命令打包报有如下错误及解决方法
查看>>
BZOJ 2338 HNOI2011 数矩形 计算几何
查看>>
关于页面<!DOCTYPE>声明
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
C++标准库vector使用(更新中...)
查看>>
cocos2d-x 2.2.6 之 .xml文件数据读取
查看>>
枚举的使用
查看>>
BZOJ 1531 二进制优化多重背包
查看>>
BZOJ 2324 (有上下界的)费用流
查看>>
python3基础06(随机数的使用)
查看>>
Zookeeper系列(二)特征及应用场景
查看>>
【HTTP】Fiddler(三)- Fiddler命令行和HTTP断点调试
查看>>