用第1个,第2个...第N个斐波那契数构成一个长度为P的序列,每个斐波那契数可以使用任意多次,但至少要使用一次,并且序列中任意两个相同的斐波那契数之间至少要隔着 M 个数, 求满足条件的序列组成方法有多少种?输出答案对1e9+7取模.
记\(fib[i]\)表示第i个斐波那契数,\(fib[0]=fib[1]=1\),\(fib[i]=fib[i?1]+fib[i?2](i>1)\).
分析:本来标题是想叫做"与fib完全无关的一道fib题".不过个人认为这的确是道思维好题.
因为题目说了所有数都要出现至少一次 所以只需考虑其组合而不用考虑其排列 最后乘个n!就是答案.(意思就是可以当做这 N 个数是无序的)所以说本题与fib无关,你就当做题目给你了n个数就行了.
设\(f[i][j]\)表示序列前i个放了j种数的方案数.考虑放第i+1个时的状态转移.
不难想到,此时我们有两种选择.
(1)放一个新的数,则状态转移为\(f[i+1][j+1]\)
(2)放一个之前已经出现过的数,则状态转移为\(f[i+1][j]\)
对于第一种情况,有\(f[i+1][j+1]+=f[i][j]\);
对于第二种情况,因为"序列中任意两个相同的斐波那契数之间至少要隔着M个数",所以序列末尾的M种数是不可以放的,则有\(f[i+1][j]+=f[i][j]*(j-m)\)
注意一边算一边取模,然后"十年oi一场空,不开long long..."
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){s=s*10+ch-‘0‘;ch=getchar();}
return s*w;
}
const int mod=1e9+7;
int n,m,p;
ll ans,f[2005][2005];
int main(){
n=read();m=read();p=read();
f[0][0]=1;
for(int i=0;i<=p;i++)
for(int j=0;j<=n;j++){
f[i+1][j+1]+=f[i][j]%mod;
if(j>m)f[i+1][j]=(f[i+1][j]+f[i][j]*(j-m))%mod;
}
ans=f[p][n]%mod;
for(int i=1;i<=n;i++)
ans=(ans*i)%mod;
cout<<ans<<endl;
return 0;
}
原文地址:https://www.cnblogs.com/PPXppx/p/10322496.html
时间: 2024-10-31 16:03:32