CF717A Festival Organization(第一类斯特林数,斐波那契数列)

题目大意:求 $\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<bits/stdc++.h>
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<mod?x+y:x+y-mod;}
inline int sub(int x,int y){return x<y?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int qpow(int a,ll b){
    int ans=1;
    for(;b;b>>=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]));
}

原文地址:https://www.cnblogs.com/1000Suns/p/11030886.html

时间: 2024-07-31 19:43:33

CF717A Festival Organization(第一类斯特林数,斐波那契数列)的相关文章

用for循环和递归调用写出1~N的斐波那契数列的和 和第N位的数

首先注意: 代码是从上往下,从左往右执行的!! 这是for循环写的 m=任意数.代表1~多少位的和 public class Fei_Bo_Na_Qi{    public static void main(String[] args){        int m = 30;  //这里代表1~30位的和        System.out.println( "斐波那契数列的第 "+m+" 位数为: "+m1(m) );//  在输出的时候调用函数    }   

javaScript实现回文数、水仙花数判断和输出斐波那契数列

    // 判断一个数是不是回文数                    // 方法一:先将数字转换成字符串,然后依次判断第一个和最后一个数字,第二个和倒数第二个数字...是否相等     function PalindromeNumber1(num){         var str = num.toString();         var flag = true;         var len = str.length;         for(var i = 0; i < (len 

给定斐波那契数列的项数求对应的数值的普通方法和优化处理

1 /** 2 给定斐波那契数列的项数求对应的数值 3 参考:剑指Offer 4 */ 5 #include <stdio.h> 6 7 int fib(int n); 8 long long fibonacci(unsigned int n); 9 int main(int argc, const char * argv[]) { 10 11 int n; 12 13 while (1) { 14 15 printf("请输入你想知道到的斐波那契数列的项数:\t"); 1

【c语言】求斐波那契数列的前40个数。特点,第1,2个数为1,从第三个数开始,该数是前面两个数之和

// 求斐波那契数列的前40个数.特点,第1,2个数为1,从第三个数开始,该数是前面两个数之和 #include <stdio.h> int main() { int a = 1; int b = 1; int c,i; printf("%d\t%d\t",a,b); for(i = 3; i <= 40; i++) { c = a + b; printf("%d\t",c); a = b; b = c; } printf("\n&quo

用递归和非递归的方法输出斐波那契数列的第n个元素(C语言实现)

费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列. 在数学上,费波那契数列是以递归的方法来定义: {\displaystyle F_{0}=0} {\displaystyle F_{1}=1} {\displaystyle F_{n}=F_{n-1}+F_{n-2}}(n≧2) 用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出.首几个费波那契系数是: 0, 1, 1, 2, 3

js算法集合(二) javascript实现斐波那契数列 (兔子数列) Javascript实现杨辉三角

js算法集合(二)  斐波那契数列.杨辉三角 ★ 上一次我跟大家分享一下做水仙花数的算法的思路,并对其扩展到自幂数的算法,这次,我们来对斐波那契数列和杨辉三角进行研究,来加深对Javascript的理解. 一.Javascript实现斐波那契数列 ①要用Javascript实现斐波那契数列,我们首先要了解什么是斐波那契数列:斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为

快速求斐波那契数列(矩阵乘法+快速幂)

斐波那契数列 给你一个n:f(n)=f(n-1)+f(n-2) 请求出 f(f(n)),由于结果很大请 对答案 mod 10^9+7; 1<=n<=10^100; 用矩阵乘法+快速幂求斐波那契数列是经典应用: 矩阵公式 C i j=C i k *C k j; 根据递推式 构造2*2矩阵: 原始矩阵 1 0 0 1 矩阵 2 1 1 1 0 原始矩阵与矩阵 2相乘达到转化状态效果: 对矩阵二进行快速幂 乘法:达到快速转化矩阵的效果: 即使达到快速转化状态:那么大的数据范围也很难求解: 高精?这有

vijos - P1543极值问题(斐波那契数列 + 公式推导 + python)

P1543极值问题 Accepted 标签:[显示标签] 背景 小铭的数学之旅2. 描述 已知m.n为整数,且满足下列两个条件: ① m.n∈1,2,-,K ② (n^ 2-mn-m^2)^2=1 编一程序,对给定K,求一组满足上述两个条件的m.n,并且使m^2+n^2的值最大.例如,若K=1995,则m=987,n=1597,则m.n满足条件,且可使m^2+n^2的值最大. 格式 输入格式 输入仅一行,K的值. 输出格式 输出仅一行,m^2+n^2的值. 样例1 样例输入1[复制] 1995

NYOJ 461-Fibonacci数列(四)(求斐波那契数列前4位)

题目地址:NYOJ 461 思路:斐波那契数列的通项公式为 然后下一步考虑如何产生前4位: 先看对数的性质,loga(b^c)=c*loga(b),loga(b*c)=loga(b)+loga(c);假设给出一个数10234432, 那么log10(10234432)=log10(1.0234432*10^7)[用科学记数法表示这个数]=log10(1.0234432)+7; log10(1.0234432)就是log10(10234432)的小数部分. log10(1.0234432)=0.0