2121: 超级玛丽
Time Limit: 1 Sec Memory Limit: 128 MB
Description
大家都知道"超级玛丽"是一个很善于跳跃的探险家,他的拿手好戏是跳跃,但它一次只能向前跳一步或两步。有一次,他要经过一条长为n的羊肠小道,小道中有m个陷阱,这些陷阱都位于整数位置,分别是a1,a2,…am,陷入其中则必死无疑。显然,如果有两个挨着的陷阱,则玛丽是无论如何也跳过不去的。
现在给出小道的长度n,陷阱的个数及位置。求出玛丽从位置1开始,有多少种跳跃方法能到达胜利的彼岸(到达位置n)。
Input
第一行为两个整数n,m
第二行为m个整数,表示陷阱的位置
Output
一个整数。表示玛丽跳到n的方案数
Sample Input
4 1
2
Sample Output
1
HINT
40>=n>=3,m>=1
n>m;
陷阱不会位于1及n上
Source
算法提高
【分析】
遇到这种问题最开始就是想到画图,看看是怎么跳的;根据题目的要求,超级玛丽跳过陷阱时,只能是从陷阱的前一个位置跳到陷阱的后一个位置,所以跳过陷阱的过程是没有多种情况的,那么多种情况就是分布在两个陷阱之间的的路程,也就是说,只需要把每一段没有陷阱的路程中的跳跃方式的种类算出来,然后相乘就好了;
每一段的跳跃方式的种类,就要用到排列组合了。
【代码】
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
int a[50];//a数组用来存放陷阱的位置
int n,m;
int main()
{
scanf("%d%d",&n,&m);
a[0]=0; //玛丽从位置1开始跳,可以假设位置0有一个陷阱,便于下面的计算
for(int i=1; i<=m; i++)
{
scanf("%d",&a[i]);
}
a[m+1]=n+1;//玛丽跳到位置n结束,可以假设位置n+1有一个陷阱
sort(a,a+m+2);//排序,很重要,之前没排序就wa了
int ans=1;
for(int i=1; i<=m+1; i++)
{
int sum1=0;
for(int j=a[i]-a[i-1]-2,k=0; j>=k; j--,k++)//开始排列组合
{
int lb=1,num=1;
for(int x=k; x>0; x--)//计算排列的分母
lb=x*lb;
for(int y1=j,y2=k; y2>0; y2--,y1--)//计算排列的分子
num=num*y1;
sum1+=num/lb;
}
ans*=sum1;
}
printf("%d\n",ans);
return 0;
}