2018-07-26 递推、递归

  • A  --(●°u°●)​ 」(两道题基本相同)

  • H -- ((゚Д゚)

  • Description

小时候我们都玩过爬楼梯的游戏:两人猜拳,赢了可向上爬一级,谁先到最高级则获胜。作为大学生,我们应该玩一个更有水平的游戏。
现在一个人要上n级楼梯,每一步可以选择上一级或者上两级,但是不能后退。求上这n级楼梯的方案数。

  • Input

第一行只有一个整数T(1<=T<=45),表示数据组数。
下面的T行每一行有一个整数n(1<=n<=45),表示有多少级楼梯。

  • Output

对于每一组数据输出一个整数s,表示方案数。

  • Sample Input

4 1 2 3 4

  • Sample Output

1 2 3 5

  • 题目理解

当你需要到达n台阶的时候由于一次只能向上一步或者向上两步,所以前一个情况你只能来自(n-1)台阶或者(n-2)台阶,则所有情况就是两数之和,思路打开和数学归纳法一样。                                                                                                                                对于A题由于是计算a-b可以直接映射到1-(b-a+1)情况完全一样得到的结果也应该一样                                                                      结果都需要用long long否则WA

A题代码:

#include<cstdio>
typedef long long ll;
const int maxn=55;
ll f[maxn];
void init(){
   f[1]=f[2]=1;
   for(int i=3;i<maxn;++i)
      f[i]=f[i-1]+f[i-2];
   //for(int i=3;i<maxn;++i)
      //printf("%lld\n",f[i]);
   return ;
}
int main()
{
    init();
    int n,a,b;
    while(scanf("%d",&n)!=EOF){
        while(n--){
            scanf("%d%d",&a,&b);
            int res=b-a+1;
            printf("%lld\n",f[res]);
        }
    }
    return 0;
}

H题代码:

#include<cstdio>
typedef long long ll;
const int maxn=55;
ll f[maxn];
void init(){
   f[0]=f[1]=1;
   for(int i=2;i<maxn;++i)
      f[i]=f[i-1]+f[i-2];
   //for(int i=3;i<maxn;++i)
      //printf("%lld\n",f[i]);
   return ;
}
int main()
{
    init();
    int t,n;
    while(scanf("%d",&t)!=EOF){
        while(t--){
            scanf("%d",&n);
            printf("%lld\n",f[n]);
        }
    }
    return 0;
}
  • B  --  _(´ཀ`」 ∠)_ (两道题基本相同)

  • K  --  =。=zzzzz B的变形?!

  • Description

一条‘Z’形线可以将平面分为两个区域,那么由N条Z形线所定义的区域的最大个数是多少呢?每条Z形线由两条平行的无限半直线和一条直线段组成

  • Input

首先输入一个数字T(T<100),代表有T次询问 每次询问输入一个数字N(N<1e8),代表有N条Z形线

扫描二维码关注公众号,回复: 2647664 查看本文章
  • Output

对于每次询问,在一行输出N条‘Z’形线所能划分的区域的最大个数为多少

  • Sample Input

2

1

2

  • Sample Output

2

12

  • 题目理解

K题:当增加第n条折线的时候最多得到9(n-1)个交点,于是我们把两端和所有交点(包括顶点看成一条弯曲的线段)把新增的折线分成9(n-1)+1条线段,仔细观察发现每条线段都会将一个已存面一分为二,所以每条线段新增一个面得到通式f(n)=f(n-1)+9*(n-1)+1求得f(n)=f(1)+\frac{9n(n-1)}{2}+(n-1)=\frac{9n^{2}-7n}{2}+1                                               

#include<cstdio>
int main()
{
    int t;
    long long n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        printf("%lld\n",(9*n-7)*n/2+1);
    }
    return 0;
}

B题:分析同理,公式推导如下:                                                                                                                                                       f(n)=f(n-1)+4*(n-1)+1求得f(n)=f(1)+\frac{4n(n-1)}{2}+(n-1)=2n^{2}-n+1                       

#include<cstdio>
int main()
{
    int c,n;
    scanf("%d",&c);
    while(c--)
    {
        scanf("%d",&n);
        printf("%d\n",2*n*n-n+1);
    }
    return 0;
}
  • D  -- /`m´)ノ ~┻━┻

  • Description

有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?

  • Input

输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),n的含义如题目中描述。
n=0表示输入数据的结束,不做处理。

  • Output

对于每个测试实例,输出在第n年的时候母牛的数量。
每个输出占一行。

  • Sample Input

2

4

5

0

  • Sample Output

2

4

6

  • 题目理解

新生的小母牛从生下来到第四个年头就可以生小母牛了,也就是说当n>4(第一年的牛可以看成新生母牛也可以不看做取决于是否等于4,两种看法答案都是一样的)的时候如第5年,这时候第2年所有的牛都会生下一头小母牛,然后加上前一年的牛,就能够得到第5年小母牛的总和,得到递推公式f(n)=f(n-1)+f(n-3)n可以从5开始也可以从4开始

//换种方式想一想第n年的时候
//n-3年的所有母牛都会生出新的母牛
//加上前一年的母牛
//就是新母牛加上就旧母牛的和
#include<cstdio>
const int maxn=60;
int f[maxn];
void init(){
    f[1]=1;
    f[2]=2;
    f[3]=3;
    f[4]=4;
    for(int i=5;i<maxn;++i)
        f[i]=f[i-1]+f[i-3];
    return ;

}
int main()
{
   init();
   int n;
   while(scanf("%d",&n)!=EOF)
   {
     if(n == 0) break;
     printf("%d\n",f[n]);
   }
   return 0;
}
  • E  -- ( ;´Д`)

  • Description

Consider all the sequences with length (0 <  N < 44), containing only the elements 0 and 1, and no two ones are adjacent (110 is not a valid sequence of length 3, 0101 is a valid sequence of length 4). Write a program which finds the sequence, which is on K-th place (0 <  K < 10 9) in the lexicographically sorted in ascending order collection of the described sequences.

  • Input

The first line of input contains two positive integers N and K.

  • Output

Write the found sequence or −1 if the number K is larger then the number of valid sequences.

  • Sample Input

3 1

  • Sample Output

000

  • 题目理解

通过前导加0或者加1得到n为下所有的合法串数量,自然得到一下的定义dp(n,0)=dp(n-1,0)+dp(n-1,1); dp(n,1)=dp(n-1,0)                                                                                                  比较巧妙的是通过k的值判断输出的是0还1,当dp(n,0)数量满足的时候第一位肯定是0然后和dp(n-1,0)比较一直类推;如果需要输出1则需要减去dp(n,0)的数量使用剩余的值来与dp(n-1,0)判断输出0还是1

#include<cstdio>
int dp[45][2];
int main()
{
    int n,k;
    dp[1][0]=dp[1][1]= 1;
    for(int i = 2; i <= 44; i++){
        dp[i][1] = dp[i-1][0];
        dp[i][0] = dp[i-1][0]+dp[i-1][1];
    }
    while(scanf("%d%d",&n,&k)!=EOF){
        if(k > dp[n][1] + dp[n][0]){
            printf("-1\n");
            continue;
        }
        while(n){
            if(dp[n][0] >= k)
                printf("0");
            else {
                k -= dp[n][0];
                printf("1");
            }
            n--;
        }
        printf("\n");
    }
    return 0;
}
  • F  -- (゚Θ゚)

  • Description

Disky and Sooma, two of the biggest mega minds of Bangladesh went to a far country. They ate, coded and wandered around, even in their holidays. They passed several months in this way. But everything has an end. A holy person, Munsiji came into their life. Munsiji took them to derby (horse racing). Munsiji enjoyed the race, but as usual Disky and Sooma did their as usual task instead of passing some romantic moments. They were thinking- in how many ways a race can finish! Who knows, maybe this is their romance! In a race there are n horses. You have to output the number of ways the race can finish. Note that, more than one horse may get the same position. For example, 2 horses can finish in 3 ways.
1. Both first
2. horse1 first and horse2 second
3. horse2 first and horse1 second

  • Input

Input starts with an integer T (≤ 1000), denoting the number of test cases. Each case starts with a line containing an integer n (1 ≤ n ≤ 1000).

  • Output

For each case, print the case number and the number of ways the race can finish. The result can be very large, print the result modulo 10056.

  • Sample Input

3

1

2

3

  • Sample Output

Case 1: 1

Case 2: 3

Case 3: 13

  • 题目理解

这道题以前做过但是还是很迷糊,对于dp状态定义十分重要,思路是对的但是由于状态定义出现问题就会发现逻辑进行不下去了而这道题应该定义f(i,j)为i匹马获得j个名次并且全部名次都有马的情况(当i!=j的时候就是出现并列名次的情况当然是前j名而不存在没有第3名并列第4名--这和苹果放进盒子存在空盒子不同)所以ans(n)= \sum_{n}^{j=1}f(i)(j)如果i\leq j情况不合理此时结果为0      而对于f(i)(j)的转移我们可以单独拿出一个马由于每个名次都有马所以我们得到两种情况

  1. 该马单独名次,则可以得到j种名次,所有情况为j*f(i-1,j-1)                                                                                     
  2. 该马和别的马并列(说明前面i-1匹马已经占据j个名次{别忘了定义}),所有情况j*f(i-1,j)      

最后我们得到f(i,j)=j*(f(i-1,j-1)+f(i-1,j))

#include<cstdio>
const int maxn=1005;
const int mod=10056;
int dp[maxn][maxn];
int ans[maxn];
int main (){
    int t;
    scanf("%d",&t);
    dp[0][0]=1;
    for(int i=1;i<maxn;i++){
        int sum=0;
        int j;
        for(j=1;j<=i;j++){
          dp[i][j]=(dp[i-1][j-1]*j+dp[i-1][j]*j)%mod;
          sum+=dp[i][j];
          sum%=mod;
        }
        ans[i]=sum;
    }
    int Case=0;
    while(t--){
        int n;
        scanf("%d",&n);
        printf("Case %d: %d\n",++Case,ans[n]);
    }
    return 0;
}
  • G  -- Can you find it?

  • Description

经典的汉诺塔问题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。Gardon就收到了一个汉诺塔玩具作为生日礼物。
  Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?

  • Input

包含多组数据,每个数据一行,是盘子的数目N(1<=N<=64)

  • Output

对于每组数据,输出一个数,到达目标需要的最少的移动数

  • Sample Input

1

3

12

  • Sample Output

1

5

81

  • 题目理解

原理和三根柱子的汉诺塔没有什么太大的区别,就是因为有第四根柱子,对于n个盘子我们可以选择其中一部分使用四根柱子移动然后因为已经有一根柱子最高处是小盘子于是不可用,然后剩下的盘子必须使用3根柱子移动,就是经典的汉诺塔问题,这里的一部分我们可以在1-n选取所以我们直接使用循环选取不同的x然后记录其中的最小值。

#include<cstdio>
#include<climits>
#include<cmath>
typedef long long ll;
ll f[65];
void init(){
    f[1]=1; f[2]=3;
    for(ll i=3;i<65;i++){
        ll minx=LONG_MAX;
        for(ll x=1;x<i;x++){
            ll res=2*f[x]+pow(2.0,i-x)-1;
            if(2*f[x]+pow(2.0,i-x)-1<minx)
                minx=2*f[x]+pow(2.0,i-x)-1;
        }
        f[i]=minx;
        //printf("%lld\n",f[i]);
    }
}

int main(){
    int n;
    init();
    while(scanf("%d",&n)!=EOF){
        printf("%lld\n",f[n]);
    }
    return 0;
}
  • I  -- (///▽///)

  • Description

HDU 2006'10 ACM contest的颁奖晚会隆重开始了!
为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:
首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;
然后,待所有字条加入完毕,每人从箱中取一个字条;
最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
大家可以想象一下当时的气氛之热烈,毕竟中奖者的奖品是大家梦寐以求的Twins签名照呀!不过,正如所有试图设计的喜剧往往以悲剧结尾,这次抽奖活动最后竟然没有一个人中奖!
我的神、上帝以及老天爷呀,怎么会这样呢?
不过,先不要激动,现在问题来了,你能计算一下发生这种情况的概率吗?
不会算?难道你也想以悲剧结尾?!

  • Input

输入数据的第一行是一个整数C,表示测试实例的个数,然后是C 行数据,每行包含一个整数n(1<n<=20),表示参加抽奖的人数。

  • Output

对于每个测试实例,请输出发生这种情况的百分比,每个实例的输出占一行, 结果保留两位小数(四舍五入),具体格式请参照sample output。

  • Sample Input

1

2

  • Sample Output

50.00%

  • 题目理解

错误率=错误可能数/总可能数                                                                                                                                                             其中总可能数为n!                                                                                                                                                                               而错误可能数的计算 ,错排思想:

当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用f(n)表示,那么f(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.

  第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;

  第二步,放编号为k的元素,这时有两种情况.

  1. 把它放到位置n,那么,对于剩下的n-2个元素,就有f(n-2)种方法;
  2. 不把它放到位置n,这时,对于这n-1个元素,有f(n-1)种方法;
#include <stdio.h>
#define N 30
double a[N], b[N];
int main(){
	int n, m;
	scanf("%d", &n);
	while (n--) {
		scanf("%d", &m);
		a[1] = 0; a[2] = 1;
		b[1] = 1; b[2] = 2;
		for (int i = 3; i <= m; i++) {
			a[i] = (i - 1) * (a[i - 1] + a[i - 2]);
			b[i] = b[i - 1] * i;
		}
		printf("%.2lf%%\n", (a[m] / b[m]) * 100);

	}
	return 0;
}
  • J  -- ・*:.。..。.:*・'(*゚▽゚*)'・*:.。. .。.:*

  • Description

We will construct an infinitely long string from two short strings: A = "^__^" (four characters), and B = "T.T" (three characters). Repeat the following steps:

  • Concatenate A after B to obtain a new string C. For example, if A = "^__^" and B = "T.T", then C = BA = "T.T^__^".
  • Let A = B, B = C -- as the example above A = "T.T", B = "T.T^__^".

Your task is to find out the n-th character of this infinite string.

  • Input

The input contains multiple test cases, each contains only one integer N (1 <= N <= 2^63 - 1). Proceed to the end of file.

  • Output

For each test case, print one character on each line, which is the N-th (index begins with 1) character of this infinite string.

  • Sample Input

1

2

4

8

  • Sample Output

T

.

^

T

  • 题目理解

找规律可以发现组合串的下标数列是3,7,10,17,27...而10-7得到的添加部分就是前面的3,17-10得到的添加部分就是前面的7,27-17是前面的10,以此类推。实际上只需要字符数组存下前面7个字符然后通过将后面的数一步步化简到1-7的范围下就可以直接输出对应的字符,使用lower_bound找到第一个大于等于的下标然后减去前面的长度得到映射到前一段组合串的下标,重复该操作一直到得到1-7的范围。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=89;
char str[10]="0T.T^__^";
ll a[maxn];
void init(){
    a[0]=0;
    a[1]=3;
    a[2]=7;
    for(int i=3;i<maxn;++i){
        a[i]=a[i-1]+a[i-2];
        //printf("%lld\n",a[i]);
    }
}
int main()
{
    init();
    ll n;
    while(scanf("%lld",&n)!=EOF){
        while(n>7){
            int lct=lower_bound(a,a+maxn,n)-a;
            n-=a[lct-1];
        };
        printf("%c\n",str[n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zm_zsy/article/details/81224258