G-Tom爬楼梯
题目描述
样例:
输入:
3
1 1
1
8 1
1
10 2
1 2
输出:
0
13
0
在这里我提供除了递归和dp的另一种解法:
思路:
先判断输入的m个数里是否有n的出现,或者是否有两个连续的数出现,如若有则输出0,继续判断下一组数据;如若不存在上述情况,则将楼梯分成m+1段,分别计算这些段的楼梯都有多少种走法,然后把这走法累乘一下就好了,过程中都要取余;
需要注意的是:每段楼梯的长度:两断点之差-1。特别的:第一段楼梯长度应为第一个断点的长度(因为开始时Tom是站在第0节楼梯上的,而且第0节不是断点),最后一段楼梯的长度应为:n减最后一个断点,第n节不是断点,所以第一段和最后一段都没有减一;
写成式子就是:
{ a[0] , i=0 //a[]储存每个断点,len[]为m+1段楼梯的长度;
len[i]={ a[i]-a[i-1]-1 , 1=<i<m
{ n-a[i-1] , i=m
献上AC代码:
#include<bits/stdc++.h>
#define LL long long
const LL mod = 1e9+7;
using namespace std;
int f[1234];
void fun()
{
f[1]=1;
f[2]=1;
for(int i=3;i<=1009;i++) //斐波那契前1000项打表
f[i]=(f[i-1]+f[i-2])%mod;
}
int main()
{
fun();
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
int a[15];
for(int i=0;i<m;i++) cin>>a[i];
sort(a,a+m);
if(a[m-1]==n){ //判断是否有n出现
cout<<0<<endl;
continue;
}
int flag=0;
for(int i=1;i<m;i++) //判断是否有连续的两个数出现
if(a[i]==a[i-1]+1){
cout<<0<<endl;
flag=1;break;
}
if(flag)continue;
LL ans=1;
ans=(ans*f[a[0]])%mod; //第一段楼梯
for(int i=1;i<m;i++)
{
ans=(ans*f[a[i]-a[i-1]-1])%mod; //中间段的楼梯
}
ans=(ans*f[n-a[m-1]])%mod; //最后一段楼梯
cout<<ans<<endl;
}
return 0;
}