• hdu递归,递推


    目录

    蟠桃记 1

    折线分割平面 2

    不容易系列之一 2

    骨牌铺方格 3

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

    Children’s Queue 3

    献给杭电五十周年校庆的礼物 3

    钥匙计数之二 3

    钥匙计数之一 3

    母牛的故事 3

    超级楼梯 3

    不容易系列之二 3

    一只小蜜蜂... 3

    阿牛的EOF牛肉串 3

    神、上帝以及老天爷 3

    不容易系列之(4)——考新郎 3

     

     

    蟠桃记

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

    #include<cstdio>

    int f(int n)

    {

    if(n==1)

    return 1;

    return f(n-1)*2+2;

    }

    int main()

    {

    int n;

    while(scanf("%d",&n)!=EOF)

    {

    printf("%d\n",f(n));

    }

    return 0;

    }

    简单题

    折线分割平面

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

    #include<cstdio>

    int main()

    {

    int t;

    int n;

    scanf("%d",&t);

    while(t--)

    {scanf("%d",&n);

    printf("%d\n",2*n*n-n+1);

    }

    return 0;

    }

    找到n=1 是f=2,n=2,f=7,n=3,f=16,根据这三个量,求出二次方程。

     

     

     

     

     

    不容易系列之一

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

    #include<cstdio>

    int main()

    {

    int n;

    while(scanf("%d",&n)!=EOF)

    {

    long long pre=0,f=0,t=-1;

    for(int i=1;i<n;++i)

    {

    t*=-1;

    f=pre*(i+1)+t;

    pre=f;

    }

    printf("%I64d\n",f);

    }

    return 0;

    }

    错位排列数Dn=nD(n-1)+(-1)^n

     

    骨牌铺方格

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

    #include<cstdio>

    int main()

    {

    int n;

    long long f[51];

    f[1]=1;f[2]=2;

    for(int i=3;i<=50;++i)

    {

    f[i]=f[i-1]+f[i-2];

    }

    while(scanf("%d",&n)!=EOF)

    {

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

    }

    return 0;

    }

    F[n]=f[n-1]+f[n-2]

    N-1是添加的牌放竖的情况,n-2是牌放横的情况。

     

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

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

    #include<cstdio>

    int main()

    {

    long long f[51];

    f[1]=3;f[2]=6;f[3]=6;

    for(int i=4;i<=50;++i)

    f[i]=f[i-1]+f[i-2]*2;

    int n;

    while(scanf("%d",&n)!=EOF)

    {

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

    }

    return 0;

    }

    先初始n=1,2,3的情况

    然后我们假设长度为n的序列,倒数第二个与第一个相同,则此时的情况有f[n-2]*2钟可能,因为倒数第二与第一相同,故最后一个有两种情况。设倒数第二个与第一个不同,则此时情况为f[n-1]*1,因为此时最后一个只能取一种可能

     

    Children’s Queue

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

    #include<cstdio>

    void add(int a[],int b[])

    {

    for(int i=0;i<100;++i)

    {

    a[i]+=b[i];

    if(a[i]>9)

    {

    ++a[i+1];

    a[i]-=10;

    }

    }

    }

    int main()

    {

    int n;

    int f[1001][100]={0};

    f[0][0]=1;

    f[1][0]=1;

    f[2][0]=2;

    f[3][0]=4;

    for(int i=4;i<1001;++i)

    {

    add(f[i],f[i-1]);

    add(f[i],f[i-2]);

    add(f[i],f[i-4]);

    }

    while(scanf("%d",&n))

    {

    int i=99;

    while(f[n][i]==0) --i;

    while(i>=0) printf("%d",f[n][i--]);

    printf("\n");

    }

    return 0;

    }

    我们假设一个合法序列,我们加上FF, M,MFFF都可以得到一个合法序列

    所以一个合法序列f[n]=f[n-1]+f[n-2]+f[n-4]

    另外这是一道高精度题。

     

    献给杭电五十周年校庆的礼物

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

    #include<cstdio>

    int main()

    {

    long long n;

    while(scanf("%I64d",&n)!=EOF)

    {

    printf("%I64d\n",(n*n*n+5*n)/6+1);

    }

    return 0;

    }

    这里转一下网上的一篇讲解

    (1) n条直线最多分平面问题

           题目大致如:n条直线,最多可以把平面分为多少个区域。

           析:可能你以前就见过这题目,这充其量是一道初中的思考题。但一个类型的题目还是从简单的入手,才容易发现规律。当有n-1条直线时,平面最多被分成了f(n-1)个区域。则第n条直线要是切成的区域数最多,就必须与每条直线相交且不能有同一交点。 这样就会得到n-1个交点。这些交点将第n条直线分为2条射线和n-2条线断。而每条射线和线断将以有的区域一分为二。这样就多出了2+(n-2)个区域。

              故:f(n)=f(n-1)+n

                           =f(n-2)+(n-1)+n

                           ……

                           =f(1)+1+2+……+n

                           =n(n+1)/2+1


             (2) 折线分平面(hdu2050)

            根据直线分平面可知,由交点决定了射线和线段的条数,进而决定了新增的区域数。当n-1条折线时,区域数为f(n-1)。为了使增加的区域最多,则折线的两边的线段要和n-1条折线的边,即2*(n-1)条线段相交。那么新增的线段数为4*(n-1),射线数为2。但要注意的是,折线本身相邻的两线段只能增加一个区域。

           

            故:f(n)=f(n-1)+4(n-1)+2-1

                           =f(n-1)+4(n-1)+1

                          =f(n-2)+4(n-2)+4(n-1)+2

                          ……

                          =f(1)+4+4*2+……+4(n-1)+(n-1)   

                          =2n^2-n+1

           (3) 封闭曲线分平面问题

           题目大致如设有n条封闭曲线画在平面上,而任何两条封闭曲线恰好相交于两点,且任何三条封闭曲线不相交于同一点,问这些封闭曲线把平面分割成的区域个数。

            析:当n-1个圆时,区域数为f(n-1).那么第n个圆就必须与前n-1个圆相交,则第n个圆被分为2(n-1)段线段,增加了2(n-1)个区域。

      

                  故: f(n)=f(n-1)+2(n-1)     

                                  =f(1)+2+4+……+2(n-1)

                                  =n^2-n+2

               (4)平面分割空间问题(hdu1290)

               由二维的分割问题可知,平面分割与线之间的交点有关,即交点决定射线和线段的条数,从而决定新增的区域数。试想在三维中则是否与平面的交线有关呢?当有n-1个平面时,分割的空间数为f(n-1)。要有最多的空间数,则第n个平面需与前n-1个平面相交,且不能有共同的交线。即最多有n-1 条交线。而这n-1条交线把第n个平面最多分割成g(n-1)个区域。(g(n)为(1)中的直线分平面的个数 )此平面将原有的空间一分为二,则最多增加g(n-1)个空间。

             

             故:f=f(n-1)+g(n-1)     ps:g(n)=n(n+1)/2+1

                        =f(n-2)+g(n-2)+g(n-1)

                        ……

                       =f(1)+g(1)+g(2)+……+g(n-1)

                      =2+(1*2+2*3+3*4+……+(n-1)n)/2+(n-1)

                      =(1+2^2+3^2+4^2+……+n^2-1-2-3-……-n )/2+n+1

                     =(n^3+5n)/6+1

    钥匙计数之二

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

    #include<cstdio>

    int main()

    {

    int n;

    long long t16=16,t2345=18,ans=104,a_2=4;

    printf("N=%d: %I64d\n",3,ans);

    for(int i=4;i<=25;++i)

    {

    t16=ans-t16+4*(1*a_2-1)+6*(a_2*2-2);

    t2345=ans+(a_2*2-2)*9;

    a_2*=2;

    ans=t16*2+t2345*4;

    printf("N=%d: %I64d\n",i,ans);

    }

    return 0;

    }

    转一份解题报告:

    二、题目分析

    提交完本题后,颇觉有递推的味道。

    出发点:构造结果ans[n]=num[1]+……+num[6];其中num[i]表示以i为最后一个槽的高度;计算出num[i],从而得出结果。

     

    首先进行初始化分析,即n=3时。

    “相连的槽其深度之差不得为5”——1,6这两个高度不能相邻;而2,3,4,5这四个高度等价,且之后n=4,5,……25的计算过程中均有此规律。即num[1]=num[6],num[2]=num[3]=num[4]=num[5],在写代码时注意到这点便可以不需要用到数组;

    num[1]=num[6]=16;num[2,3,4,5]=18;

    ans[3]=104;

     

    (下面是重点)

    再由n-1递推分析n的情况:

    1、 当前面n-1个排列是钥匙的排列,则

    A、 对2,3,4,5作为第n个高度来说都能满足题意,有num[2,3,4,5]=ans[n-1];

    B、 对1,6(1,6等价,记号不同而已)来说,第n-1个高度不能为6,1,即要去掉

    几个不符合题意的组合;num[1]=ans[n-1]-num__[6](前n-1个中最后一个为6的个数,实际写代码时要用另一个数组保存)。同理 num[6]=ans[n-1]-num__[1](……)。也即num[1,6]=ans[n-1]-num__[6](……);

     

    2、 当前面n-1个排列不是钥匙的排列,则

    A、对i(i=2,3,4,5)作为第n个高度来说能满足钥匙的要求,则说明前面n-1个排列里仅有两类高度,且与i不同,加上i就刚好3类高度满足题意。那么前面两类高度的选法总数是从其余5类高度里选出两类,即C(5,2),但1,6不能同时选,故组合数为

    C(5,2)-1。 再看排列数,n-1个位置,每个位置可任选两类,但不能全部是同一类高度,故排列数2^(n-1)-2。

    B、对i=1,6,同上面分析。因为1,6等价,所以我这里举i=1来说,前面两类高度里我有两种取法,选6和不选6。

    对于选6,组合数是C(4,1)(剩下2,3,4,5任意选一);再看排列数,每个位置可任选两类,但不能全部是同一高度,且最后一个也即第n-1个位置处不能为6,也可换个说法,最后一个位置放i(i=2,3,4,5),前面n-2个位置任选6和i放,排列数4×2^(n-2)。

    对于不选6,组合数是C(4,2);再看排列数,每个位置可任选两类,且不能全部是同一类高度,排列数2^(n-1)-2。

     

    把上面的组合数与排列数相乘便得到一种情况下的num[i]的值,所有情况的值相加便得到结果。

     

    三、代码(从简)

    /*Accepted 1480 0MS 192K 743B G++ */

        

        t[6]=16;ans[3]=104;

        for(i=4;i<26;i++)

        {

            //前n-1是钥匙的情况;

            num[1]=ans[i-1]-t[6];

            num[2]=ans[i-1]; 

            

    //前n-1不是钥匙的情况;

            num[1]+=c42*(mult(2,i-1)-2);   //不含有6;mult()算阶乘;

              

            num[1]+=4*(mult(2,i-2)-1);   //含有6;

              

            num[2]+=(c52-1)*(mult(2,i-1)-2);

              

            ans[i]=2*num[1]+4*num[2];

            t[6]=num[1];

        }

       

    /*以上代码可以不写mult函数,在数据量大的情况下能省很多时间,请读者自己思考,

    以上代码可以不写数组,在数据量大的情况下能省内存占用。希望读者完善之*/

    四、总结(略)

    刚开始接触这题,有点恐惧,尽管自己手动分析了n=3,4的情况,感觉情况似乎很多种,不敢往下接着想,和以前做这类题一样,以为会有什么很高深的数学公式可以用,就没有继续下去。

    AC完后就会有似曾相识的感觉,类似于http://acm.hdu.edu.cn/showproblem.php?pid=3284

    这类由n-1递推到n的题,其实还有好几道,只是一时没找不到,发现这类题的共同点就是选定某个位置作为结果的一部分,用数组保存,n-1到n之间由这个数组来递推。本题hdu1480网上还有一个十分详细的解题报告(http://www.programfan.com/blog/article.asp?id=45140),本人未看,不知是否大体相同,若看不懂本解题报告,可参考之。

     

       hdu 1480  钥匙计数之二  

     

     一把钥匙有N个槽,2<N<26槽深为1,2,3,4,5,6。每钥匙至少有3个不同

     的深度且相连的槽其深度之差不得为5。求这样的钥匙的总数。

     

    解题分析

     

    key[n]是有n个槽的钥匙的总数,

    num[i]是最后一个槽的高度为i的钥匙总数 

    n=3时

       abc 是 钥匙且c=1,

       则 b!=6,b=2,3,4,5有4种,a是除c,b 外的4种,因此有

       3个槽且最后一个槽高为1的 钥匙有 16种,记为 num[1]=16; 

     

      如果 abc是 钥匙, 则 (7-a)(7-b)(7-c) 也是

      例如  1234是 钥匙 则 6543 也是

      这说明 num[i]=num[7-i],num[1]=num[6];

      

       abc 是 钥匙且c=2,

       则 a,b 是 1,3,4,5,6中挑2个但不挑(1,6),有c(5,2)-1=9种,因此有

       3个槽且最后一个槽高为2的 钥匙有 9*2=18种, num[2]=18; 

      易知 num[2]=num[3]=num[4]=num[5]; 

    n=3, key[3]=num[1]+...+num[6]=104;

     

     

    设num[i]和temp[i]分别是n-1和n个槽的最后槽高为i的钥匙总数

     

    1、 设 **** 是n-1个槽的钥匙,则 ****d是 n个槽的钥匙,d=2,3,4,5.

        即temp[d]=key[n-1]+s;

        设 **** 不是n-1个槽的钥匙, ****d是 n个槽的钥匙,d=2,3,4,5.

        则 ****是除d外的两个数字构成且这两个数字不能是(1,6) ,有

        s=(c(5,2)-1)*(2^(n-1)-2)=9*(2^(n-1)-2)种

        即

        temp[d]=key[n-1]+ 9*(2^(n-1)-2);

        

    2  设 **** 是n-1个槽的钥匙且最后槽高不为6,则 ****1是 n个槽的钥匙。

        即

        temp[1]=key[n-1]-num[6]+s;

        设 **** 不是n-1个槽的钥匙, ****1是 n个槽的钥匙

        则 **** 由2,3,4,5中的两个构成 

        有c(4,2)*(2^(n-1)-2)种,再加

        ****由2,3,4,5中的1个和6构成6不能是最后一个

        有4*(2^(n-2)-1)种

       即

       temp[1]=key[n-1]-num[6]+ 6*(2^(n-1)-2)+ 4*(2^(n-2)-1);

       

             = key[n-1]-num[6]+ 16*(2^(n-2)-1)  

       temp[6]=temp[1];

       

       for(n=4;n<=25;n++)

       {

                         

        key[n]=................. 

                         

       }

     

    钥匙计数之一

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

    #include<cstdio>

    int main()

    {

    int n;

    long long t14=4,t23=4,ans_1=16,ans_2=24,a_2=4;

    printf("N=2: 0\n");

    printf("N=3: %I64d\n",ans_2-ans_1);

    for(int i=4;i<=31;++i)

    {

    t14=ans_1-t14+(a_2*2-2)+2*(a_2-1);

    t23=ans_1+2*(a_2*2-2);

    ans_1=t14*2+t23*2;

    ans_2=(ans_2+3*(a_2*2-2))*4;a_2*=2;

    printf("N=%d: %I64d\n",i,ans_2-ans_1);

    }

    return 0;

    }

    由上一道题改编而成,思想差不多。

     

    母牛的故事

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

    #include<cstdio>

    int main()

    {

    int n;

    int f[56];

    f[1]=1;f[2]=2;f[3]=3;

    for(int i=4;i<54;++i)

    f[i]=f[i-3]+f[i-1];

    while(scanf("%d",&n),n)

    {

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

    }

    return 0;

    }

    列出前几项,可推出fibonacci序列。

     

    超级楼梯

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

    #include<cstdio>

    int main()

    {

    int f[41];

    f[1]=1;f[2]=1;

    for(int i=3;i<=40;++i)

    f[i]=f[i-1]+f[i-2];

    int t,n;

    scanf("%d",&t);

    while(t--)

    {scanf("%d",&n);

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

    }

    return 0;

    }

    典型的fibonacci序列

     

    不容易系列之二

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

    #include<cstdio>

    int f(int i)

    {

    if(i==0)

    return 3;

    return f(i-1)*2-2;

    }

    int main()

    {

    int n;

    scanf("%d",&n);

    while(n--)

    {

    int a;

    scanf("%d",&a);

    printf("%d\n",f(a));

    }

    return 0;

    }

     

    简单的递归题,懒得写成迭代形式。

     

    一只小蜜蜂...

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

    #include<cstdio>

    int main()

    {

    int n;

    long long f[50];

    f[1]=1;f[2]=1;f[3]=2;

    for(int i=4;i<50;++i)

    {

    f[i]=f[i-1]+f[i-2];

    }

    int a,b;

    scanf("%d",&n);

    while(n--)

    {

    scanf("%d%d",&a,&b);

    printf("%I64d\n",f[b-a+1]);

    }

    return 0;

    }

    一个路径的可能数=他前面两个路径之和。

     

     

    阿牛的EOF牛肉串

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

    #include<cstdio>

    int main()

    {

    int n;

    long long f[40];

    f[1]=3;f[2]=8;

    for(int i=3;i<40;++i)

    f[i]=f[i-1]*2+2*f[i-2];

    while(scanf("%d",&n)!=EOF)

    {

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

    }

    return 0;

    }

    分两种情况讨论,一种是最后一个为EF,一种是最后一个为O,则倒数第二个肯定为EF。

     

    神、上帝以及老天爷

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

    #include<cstdio>

    #include<cmath>

    int main()

    {

    int n;

    long long s=1;

    long long f[21];

    long long g[21];

    f[2]=1;

    f[3]=2;

    g[2]=2;

    g[3]=6;

    for(int i=4;i<=20;++i)

    {

    f[i]=(i-1)*f[i-1]+(i-1)*f[i-2];

    g[i]=g[i-1]*i;

    }

    int t;

    scanf("%d",&t);

    while(t--)

    {

    scanf("%d",&n);

    printf("%.2lf%%\n",double(f[n])/g[n]*100);

    }

    return 0;

    }

    错位排列 假设第一个位置被除1以为的占据,则剩下的序列可分为:

    第一个位置被1占据和不被1占据两种情况。

    从而f[n]=(n-1)*f[n-1]+(n-1)*f[n-2];

     

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

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

    #include<cstdio>

    int main()

    {

    long long  f[21],g[21];

    f[1]=0;f[2]=1;f[3]=2;g[1]=1;g[2]=2;g[3]=6;g[0]=1;

    for(int i=4;i<=20;++i) 

    {

    f[i]=(i-1)*(f[i-1]+f[i-2]);

    g[i]=g[i-1]*i;

    }

    int n;

    scanf("%d",&n);

    while(n--)

    {

    int m,n;

    scanf("%d%d",&n,&m);

    printf("%I64d\n",g[n]/g[n-m]/g[m]*f[m]);

    }

    return 0;

    }

     思想跟上题差不多。。

     

    Counting Triangles

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1629

    #include<iostream>

    using namespace std;

    int main()

    {

    int n;

    int a[520]={0};

    for(int i=1;i<=500;i++)

    {

    a[i]=a[i-1]+(i+1)*i/2+((i-1)+1)*i/4;

    }

    while(cin>>n)

    {

    cout<<a[n]<<endl;

    }

    return 0;

    }

    说明:由小到大推导,n可以由n-1推导出来:

    a[n]=a[n-1]+(n+1)*n/2+((n-1)+1)*n/4

    n长的三角形由n-1长的三角形 加上1行三角形组成,我们只需考虑,加上1行后 生成的三角形数就可以了,(n+1)*n/2是计算生成上三角形的数目,((n-1)+1)*n/4是计算生成下三角形的数目。

    本来我是这样写的:

    a[i]=a[i-1]+(i+1)*i/2+(n%2?((i-1)+2)*i/4:(i-1)+1)*i/4)

    但反而出错,可能是由于整数计算时约掉了小数部分的缘故。

     

    Steps

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1871

    #include<iostream>

    #include<cmath>

    using namespace std;

    int main()

    {

    long long x,y;

    long long dif;

    while(cin>>x>>y)

    {

    dif=y-x;

    if(dif==0)//考虑0的情况

    {

    cout<<0<<endl;

    continue;

    }

    long long r=ceil(sqrt(double(dif)));//平方后向上取整

    long long m=1+(r-1)*2;

    if(r*r-dif>=r)

    m--;

    cout<<m<<endl;

    }

    return 0;

    }

    说明:主要是规律的查找和公式的推导

    1 1

    2 2

     

    3 3

    4 3

    5 4

    6 4

     

    7 5

    8 5

    9 5

    10 6

    11 6

    12 6

    由以上的规律 推导出公式即可,我们可以看到 9开方为3 恰好是 连续值为5的个数,而5恰好=(3-1)*2+1,5~9开方取上整皆为 3,对于9和9之前的三个数,可以直接去(3-1)*2+1,对于7之前的两个数 (3-1)*2+1减一就能得到答案。

    同理 2~4,13~16也是如此。

    最后还得考虑0这个特殊情况。

    这道题虽归属于简单题,但值得收藏。

     

  • 相关阅读:
    Windows下配置nginx+php(wnmp)
    nginx缓存优先级(缓存问题者必看)
    OpenResty(Nginx)+Lua+GraphicsMagick实现缩略图功能
    M3U8文件简介
    拼车旅游网站 导航
    将jsp页面内容保存到excel(转)
    queryRuner如何获得bean对象,当这个bean对象中包含其他对象的时候
    js的trim方法(转)
    二进制运算误差问题
    myeclipes如何调试web项目
  • 原文地址:https://www.cnblogs.com/PegasusWang/p/2975801.html
Copyright © 2020-2023  润新知