HDU-#2044-2050 递推求解专题

来源:互联网 发布:wav播放软件 编辑:程序博客网 时间:2024/05/19 06:18

        HDU的#2044-2050是递推专题训练,递推关系在数学专题中是很重要的一部分,也是规律性和技巧性很强的一部分。下面给出这个专题的解题报告如下:

        专题来源:【HDU递推求解专题训练题】


        #2044:一只小蜜蜂...

       解题思路:直接递推可以发现,从1开始到每一个点的走法为:1 ,2,3,5,8....这时候很清晰的数列出现在我们面前,那就是斐波那契数列。而问题是要求给出起点到终点的走法,而不是1。但是我们反过来想想,从任何点开始走与从1开始走到他们之间差值那个点的结果是一致的。因此该问题只是斐波那契数列的变形,将a,b的差值作为n即可得到,详见code。

       题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2044

       code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 50+10;int n,a,b;ll f[MAXN];int main(){    f[0]=1;f[1]=1;    for(int i=2;i<MAXN;i++)        f[i]=f[i-1]+f[i-2];    scanf("%d",&n);    while(n--){        scanf("%d%d",&a,&b);        printf("%I64d\n",f[b-a]);    }    return 0;}

        #2045:不容易系列之(3)—— LELE的RPG难题

        解题思路:找不到好的思路时,我们先枚举结果,可以得到:f[1]=3,f[2]=6,f[3]=6,f[4]=18,f[5]=30....,根据枚举的数列可以推导出该递推公式:f[i]=f[i-1]+2*f[i-2],这里数据量不大时可以直接枚举找下规律,要注意边界为:f[1]=3,f[2]=6,f[3]=6。注意数据范围,用__int64来存。详见code。

        题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2045

        code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 50+10;int n;ll f[MAXN];int main(){    f[1]=3;f[2]=6;f[3]=6;    for(int i=4;i<MAXN;i++)        f[i]=f[i-1]+2*f[i-2];    while(scanf("%d",&n)!=EOF)        printf("%I64d\n",f[n]);    return 0;}

       #2046:骨牌铺方格

      解题思路:这是一道经典的题目。首先先考虑最左边一列的铺法,若用一个直接纵向覆盖,则剩下的2*(n-1)方格有f(n-1)种铺法;若用两个横向的覆盖,则剩下的2*(n-2)有f(n-2)种铺法。因此递推可以得到f(n)=f(n-1)+f(n-2),边界f(0)=f(1)=1.恰好就是斐波那契数列,直接就可以求解。不过这里还有一种推法,就是考虑第i列纵向骨牌,则左边的i-1列和右边的n-i列各有f(i-1)和f(n-i)种铺法,根据乘法原理以及去掉重复的和加上遗漏的,可以得到另一种递推式:1、当n为偶数的时候,f(n)=1+f(1)+f(3)+...+f(n-1),其中1为没有纵向的情况;2、当n为奇数的时候,f(n)=f(0)+f(2)+f(4)+...+f(n-1)。边界为:f(0)=f(1)=1。因此这也很好地说明了递推式可能存在多种,这也是它规律性和技巧性很强的原因之一。还有就是不完善的解法可以通过打补丁来修复,不过这需要很强的逻辑和理论。解法详见code哈!

      题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2046

     斐波那契数列 code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 50+10;int n;ll f[MAXN];int main(){    f[0]=1;f[1]=1;    for(int i=2;i<MAXN;i++)        f[i]=f[i-1]+f[i-2];    while(scanf("%d",&n)!=EOF)        printf("%I64d\n",f[n]);    return 0;}

      另一种code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 50+10;int n;ll f[MAXN];int main(){    f[-1]=1;f[0]=1;f[1]=1;    for(int i=2;i<MAXN;i++){        if(i%2==0) for(int j=-1;j<MAXN;j+=2) f[i]+=f[j];        else for(int j=0;j<MAXN;j+=2) f[i]+=f[j];    }    while(scanf("%d",&n)!=EOF)        printf("%I64d\n",f[n]);    return 0;}

       #2047:阿牛的EOF牛肉串

      解题思路:给长度为n的字符串,由EOF三个字符组成,排除OO相连的情况的有多少种组合。直接找规律递推就行。首先分两种情况:一是当第i位为O的时候,则i-1位只能是E or F,对于剩下n-2的情况为f(n-2),则该递推式为1*2*f[n-2];二是当第i位为E or F的时候,那么n-1位为f(n-1),该情况递推式为2*f[n-1]。综上,该递推式为f[n]=2*(f[n-1]+f[n-2]).详见code。

      题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2047

     code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 40+5;int n;ll f[MAXN];int main(){    f[1]=3;f[2]=8;    for(int i=3;i<MAXN;i++)        f[i]=2*(f[i-1]+f[i-2]);    while(scanf("%d",&n)!=EOF)        printf("%I64d\n",f[n]);    return 0;}

       #2048:神、上帝以及老天爷

      解题思路:这是一个错排问题。先求解错排的数量,然后除以全排的数量就是答案。对于错排情况:对于第n个人,则他的选取方法为n-1种;若选取第i个人的,此时有两种情况,一是该人选取的是第n个人的,则剩余的就是n-2种错排。第二种是不选取第n个人,则此时剩下的n-1种要错排。综上递推式为:f(n)=(n-1)*(f(n-1)+f(n-2))。详见code。

      题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2048

     code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 21;ll c[MAXN],f[MAXN];int t,n;int main(){    c[1]=1;    for(int i=2;i<=MAXN;i++)        c[i]=c[i-1]*i;    f[1]=0;f[2]=1;    for(int i=3;i<=MAXN;i++)        f[i]=(i-1)*(f[i-1]+f[i-2]);    scanf("%d",&t);    while(t--){        scanf("%d",&n);        printf("%.2lf%%\n",100*(double)f[n]/c[n]);    }    return 0;}

       #2049:不容易系列之(4)——考新郎

      解题思路:该题是上题的一种变形的,原则上也是一种错排问题,这里要注意(n-m)个人是正确的排列,此时错排的数量要和这(n-m)个进行组合,即c(n,m)*f(n)。这里就不赘述了,详见code。

      题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2049

     code:

#include <iostream>#include <cstdio>using namespace std;#define ll __int64const int MAXN = 21;ll c[MAXN],f[MAXN];int t,n,m;int main(){    c[0]=1;c[1]=1;    for(int i=2;i<=MAXN;i++)        c[i]=c[i-1]*i;    f[0]=0;f[1]=0;f[2]=1;    for(int i=3;i<=MAXN;i++)        f[i]=(i-1)*(f[i-1]+f[i-2]);    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        printf("%I64d\n",c[n]/c[m]/c[n-m]*f[m]);    }    return 0;}

       #2050:折线分割平面

      解题思路:这个题比较经典,这里参见了这篇博客,这里讲的比较详细和清楚,规律性比较强,直接递推就可以出来了,就不赘述了,详见code。

      题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2050

     code:

#include <iostream>#include <cstdio>using namespace std;int n,t;int main(){    scanf("%d",&t);    while(t--){        scanf("%d",&n);        printf("%d\n",2*n*n-n+1);    }    return 0;}
0 0
原创粉丝点击