题目
求
。
。
题解
假设问题是问每次只加1或2,加到
的方案数。
则
。
斐波那契?
没错。
用
的另一种方法求,就是求
。
倒着推不好推?那就顺着推。
那么这道题目就将2替换为
,加到的目标数在区间
。
假设现在已经加到了
,则加
就可以达到目标。
假设现在已经加到了
,则加
就可以达到目标。
难点难在加到的目标数属于一个区间。
对于第一种情况,枚举加了多少个
,则加的
的个数也确定了。你会发现除法有余数。这个余数的范围就对应着区间
。
对于第二种情况,枚举加了多少个
,则加的
的个数也确定了。你会发现除法有余数。这个余数的范围就对应着区间
。
所以就可以愉快地做题了。
心得
从大神们那里得知,问题 都可以用时间复杂度为 的算法求出答案。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000010
#define DB double
#define LL long long
#define mo 1000000007
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const DB pi=acos(-1);
LL i,j,n,m,ans;
LL jc[N],ny[N];
LL ksm(LL x,LL y){
LL rs=1;
for(;y;y>>=1,x=(x*x)%mo)if(y&1)rs=(rs*x)%mo;
return rs;
}
void pre(){
LL i;
jc[0]=jc[1]=ny[0]=ny[1]=1;
fo(i,2,N-10)jc[i]=(jc[i-1]*i)%mo;
ny[N-10]=ksm(jc[N-10],mo-2);
fd(i,N-11,2)ny[i]=(ny[i+1]*(i+1))%mo;
}
LL C(LL n,LL m){return ((jc[n]*ny[m])%mo*ny[n-m])%mo;}
void add(LL &x,LL y){x=x+y>=mo?x+y-mo:x+y;}
int main(){
scanf("%lld",&n);
if(n<4){printf("1");return 0;}
pre();
fo(i,0,n-4){
j=(DB)(n-4-i)/pi;
add(ans,C(i+j,i));
}
m=(n-4)/pi;
fo(i,0,m){
j=(DB)(n-4-i*pi);
add(ans,C(i+j,i));
}
printf("%lld",ans);
return 0;
}