hdu 2044-2050 递推专题

总结一下做递推题的经验,一般都开成long long (别看项数少,随便就超了) 一般从第 i 项开始推其与前面项的关系(动态规划也是这样),而不是从第i

项推其与后面的项的关系。

hdu2044:http://acm.hdu.edu.cn/showproblem.php?pid=2044

//没开成long long WA了一次
#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;

long long f[52][52];///表示a - b的方案数
int main()
{
    for(int i=0;i<50;i++){
        f[i][i]=0;
        f[i][i+1]=1;
        f[i][i+2]=2;
    }
    for(int i=1;i<50;i++){
        for(int j=i+3;j<50;j++){
            f[i][j]=f[i][j-1]+f[i][j-2];
        }
    }
    int tcase;
    scanf("%d",&tcase);
    while(tcase--){
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%lld\n",f[a][b]);
    }
    return 0;
}

hdu2045:http://acm.hdu.edu.cn/showproblem.php?pid=2045

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;
///第 n 种方案由前 n-1种方案决定
///如果 第 n-1 个格子和 第 1个格子涂色方案不同,那么第n个格子可选方案只有一种, f[n] = f[n-1];
///若第n-1个格子和第1个格子相同,此时为f(n-2)再乘第n-1个格子的颜色数,这样为2*f(n-2);
long long f[51];
int main()
{
    f[1]=3;
    f[2]=6;
    f[3]=6;
    for(int i=4;i<=50;i++) f[i]=f[i-1]+2*f[i-2];
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        printf("%lld\n",f[n]);
    }

    return 0;
}

hdu 2046:http://acm.hdu.edu.cn/showproblem.php?pid=2046

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;
///前 i 个格子如果在第i列放竖着放一根1*2的格子,那么 f[i] = f[i-1]
///如果在第 i-1列和第 i列横着放两根1*2的格子,那么f[i] = f[i-2]
///f[i] = f[i-1]+f[i-2]
long long f[51];
int main()
{
    f[1]=1;
    f[2]=2;
    for(int i=3;i<=50;i++) f[i]=f[i-1]+f[i-2];
    int n;
    while(scanf("%d",&n)!=EOF){

        printf("%lld\n",f[n]);
    }

    return 0;
}

hdu 2047:http://acm.hdu.edu.cn/showproblem.php?pid=2047

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;
///如果第 n个字符为 ‘E‘或者‘F‘,那么前n-1个没有任何限定 f[n] = 2*f[n-1]
///如果为‘O‘ ,那么第 n-1个格子只能选‘E‘或‘F‘,前n-2没有限定,f[n] = 2*f[n-2]
///f[n]=2*f[n-1]+2*f[n-2]
long long f[41];
int main()
{
    f[1] = 3;
    f[2] = 8;
    for(int i=3;i<40;i++) f[i]=2*f[i-1]+2*f[i-2];
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        printf("%I64d\n",f[n]);
    }

    return 0;
}

hdu 2048:http://acm.hdu.edu.cn/showproblem.php?pid=2048

这题开始不会做。。然后知道了错排公式:错排公式

果然弄数学功底很重要啊。。然后就很容易了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;

///错排:考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,
///那么这样的排列就称为原排列的一个错排。
///当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用D(n)表示,那么
/// D(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.
///第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
///第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于
///第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;⑵第k个元素不把它放到位置n,这时,对于
///这n-1个元素,有D(n-1)种方法;
///所以得到错排公式:f[i] = (i-1)*(f[i-1]+f[i-2])

///解题思路:错排除以全排列 (有意思的是,到8以后这个几率就恒定了)
long long f[21];
int main()
{
    f[1] = 1;
    f[2] = 1;
    f[3] = 2;
    for(int i=4;i<=20;i++) f[i]=(i-1)*f[i-1]+(i-1)*f[i-2];
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        int n;
        scanf("%d",&n);
        long long k =1;
        for(int i=1;i<=n;i++) k*=i;
        printf("%.2lf%%\n",f[n]*1.0/k*100);
    }

    return 0;
}

hdu 2049:http://acm.hdu.edu.cn/showproblem.php?pid=2049

知道错排公式就会了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;
///M个数有f[M]种错排,N里面选M个数有C(M,N)=n!/(m!*(n-m)!) = n!/m!/(n-m)!种可能,
///所以 f[M]*C(M,N)即为所求
long long f[21];
int main()
{
    f[1] = 1;
    f[2] = 1;
    f[3] = 2;
    for(int i=4;i<=20;i++) f[i]=(i-1)*f[i-1]+(i-1)*f[i-2];
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        long long k =1;
        int t = n-m;
        for(int i=n;i>m;i--){
            k*=i;
            while(k%t==0&&t!=1){
                k=k/t;
                t--;
            }
        }
        printf("%lld\n",f[m]*k);
    }

    return 0;
}

hdu 2050:http://acm.hdu.edu.cn/showproblem.php?pid=2050

我按照自己的想法做,然后AC了。。但没法证明。。。具体证明看这里:http://www.cnblogs.com/chaosheng/archive/2012/01/26/2329583.html

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <string.h>
#include <math.h>
using namespace std;

///这个题没两条折线之间要分割的平面尽可能的多,那么每两条之间都会有四个交点
///所以当n条折线时,会多出4*n*(n-1)/2个点。。然后我加上原来的n个顶点,就得到所有顶点的个数
///然后+1就是答案。。
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        int n;
        scanf("%d",&n );
        printf("%d\n",2*n*n-n+1);
    }

    return 0;
}
时间: 2024-08-04 07:27:34

hdu 2044-2050 递推专题的相关文章

HDU 2044(递推&amp;递归_A题)解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2044 ------------------------------------------------------------------------------------ 题意:只能爬向+1或者+2的房间,求第a个房间到第b个房间的路线多少. 思路:递归,爬向第k个房间只能从第k-1或者k-2个房间爬动,所以相加递归即可. 注意: 递归的题目一般要用数组存上所求的解,防止给出较大值时造成的TLE

递推专题笔记

递推说白了就是找规律,然后写出他的递推方程,有的还可以写出通项公式,然后准确预测出第n项的值.因为这种规律存在着前因后果的关系,即是说,后一项的结果往往和前一项或前几项有着某种联系.这种联系不仅仅存在于数字之中,世间万物亦是如此. 由于,递推是深入理解动态规划的基础,就我目前的水平,看到动态规划就如看到tiger一般,完全不知所以,所以为了找回在动态规划前的自信,我打算在回家之前,找一个递推专题练练手.现记录如下: 心得: 1. 既然是递推题,那么肯定有递推方程,那么同样有规律可循,既然有规律.

简单递推专题

Computer Transformation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6084    Accepted Submission(s): 2222 Problem Description A sequence consisting of one digit, the number 1 is initially wri

HDU 2013(递推&amp;递归_D题)解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2013 ----------------------------------------------------------------------------------- 题意:每天吃掉一半再多一个,给出第几天吃到只剩一个,求开始时的数量. 思路:递推.按照每天的处理方式反向处理一下,最终得到结果. 代码: #include<cstdio> #include<cstring> #in

HDU 2045(递推&amp;递归_B题)解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2045 ----------------------------------------------------------------------------------- 题意:3种颜色,方格涂色,从左到右,最后一个方格颜色不能和第一个方格颜色相等,相邻颜色不能相同. 思路:最开始思路想简单了,以为第一个方格3种颜色,第二个方格到倒数第二个方格都是2种选择,最后一个方格一种选择.但是,这种递推需要

hdu 2067(递推或卡特兰数【待补充】)

//解法一:递推#include<iostream> using namespace std; long long d[36][36]; int main() { for(int i=1;i<=35;i++) { d[0][i]=1; } for(int i=1;i<=35;i++) for(int j=i;j<=35;j++) { if(i==j) d[i][j]=d[i-1][j]; else d[i][j]=d[i-1][j]+d[i][j-1]; } int n; i

hdu 1249 三角形 (递推)

三角形 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4390    Accepted Submission(s): 2957 Problem Description 用N个三角形最多可以把平面分成几个区域? Input 输入数据的第一行是一个正整数T(1<=T<=10000),表示测试数据的数量.然后是T组测试数据,每组测试数据只

HDU 2604 Queuing (递推+矩阵快速幂)

[题目链接]:click here~~ [题目大意]: n个人排队,f表示女,m表示男,包含子串'fmf'和'fff'的序列为O队列,否则为E队列,有多少个序列为E队列. [思路]: 用f(n)表示n个人满足条件的结果,那么如果最后一个人是m的话,那么前n-1个满足条件即可,就是f(n-1): 如果最后一个是f那么这个还无法推出结果,那么往前再考虑一位:那么后三位可能是:mmf, fmf, mff, fff,其中fff和fmf不满足题意所以我们不考虑,但是如果是 mmf的话那么前n-3可以找满足

hdu 1723 DP/递推

题意:有一队人(人数 ≥ 1),开头一个人要将消息传到末尾一个人那里,规定每次最多可以向后传n个人,问共有多少种传达方式. 这道题我刚拿到手没有想过 DP ,我觉得这样传消息其实很像 Fibonacci 所举的例子:一个人每次能够跨一或二阶台阶,问到 n 阶台阶有几种跨法.理念是一样的,只不过跨得台阶数可能会变而已.根据 Fibonacci 数列类比过来,每次最多能传 m 人,则 A [ i ] = A [ i - m ] + A [ i - m + 1 ] +  …… + A [ i - 1