递推经典例题

种小花

为了美化环境,市长提出全民种花活动:第一户种1盆,第二户种1盆,第三户种2盆,第四户种3盆,第五户种5盆,第六户种8盆……以此类推,请问第n户要种多少盆?

输入格式

1个整数n,代表第几户(n<1000)。

输出格式

1个整数,代表第n户要种花的盆数。

输入/输出例子1

输入:

10

输出:

55

提示

这道题其实就是斐那次波求第n项。

代码:
#include<bits/stdc++.h>
using namespace std;
int sum(int n)
{
    if(n<=2)return 1;//出口
    return sum(n-1)+sum(n-2);//进行递推
}
int n;
int main(){
    cin>>n;
    cout<<sum(n);
    
    return 0;
}

骨牌2

有2×n的一个长方形方格,用一个1×2的骨牌铺满方格。 
例如n=3时,为2×3方格。此时用一个1×2的骨牌铺满方格,共有如下3种铺法: 

微信图片_20220123170110.png


试对给出的任意一个n(n>0),求出铺法总数。 

输入/输出例子1

输入:

2

输出:

2

代码:
#include<bits/stdc++.h>
using namespace std;
int n;
long long f[10005];
int main(){
    cin>>n;
    f[1]=1;f[2]=2; 
    for(int i=3;i<=n;i++)
        f[i]=f[i-1]+f[i-2];
    cout<<f[n];
    return 0;

}

蜜蜂路线简化版

一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:
蜜蜂从蜂房M开始爬到蜂房N,1<=M< N<=50,有多少种爬行路线?

pimg2073_1.jpg

输入格式

输入M,N的值。

输出格式

爬行有多少种路线。

输入/输出例子1

输入:

1 14

输出:

377

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[10005];
int main(){
    cin>>n>>m;
    int ans=(m-n+1);
    a[1]=1,a[2]=1;
    for(int i=3;i<=ans;i++)
        a[i]=a[i-1]+a[i-2];
    cout<<a[ans];
    return 0;
}

找规律

一列数的前几个数分别为0、1、1、2、4、7、13、……,请你根据这个规律编程输出此数列的第n项的数值。

输入格式

一个整数n(2≤n≤40),表示求第n项。 

输出格式

一个整数m,表示第n项的数值。

输入/输出例子1

输入:

10

输出:

81

代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[100005];
int main(){
    cin>>n;
    a[0]=0;
    a[1]=1;
    a[2]=1;
    for(int i=3;i<n;i++)
        a[i]=a[i-1]+a[i-2]+a[i-3];
    cout<<a[n-1];
    
    return 0;
}

数列一

数学课上,老师在黑板上写下了如下的一串数:

1、2、3、1、4、3、7、4、11、7……

请你根据它的规律求出第N项的值?

细心的明明发现这个数列的规律是:奇数项等于前一个奇数项加前一个偶数项,偶数项等于前一个奇数项减前一个偶数项。

由于计算结果有点大,明明怕算错,你能帮他算出来吗? 

输入格式

输入只有一个数N(3<=N<=100)

输出格式

输出数列中第N个数的值。

输入/输出例子1

输入:

6

输出:

3

代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[10000005];
int main(){
    cin>>n;
    a[1]=1;
    a[2]=2;
    a[3]=3;
    for(int i=4;i<=n;i++)
    {
        if(i%2==0){
            a[i]=a[i-1]-a[i-2];
        }
        else{
            a[i]=a[i-1]+a[i-2];
        }
    }
    cout<<a[n];
    return 0;
}

序列

给出一个序列:10,20,11,19,12,18,......根据序列的规律,第N项是什么?

输入格式

一个整数N。

输出格式

一个整数

输入/输出例子1

输入:

7

输出:

13

数据范围:

1 <= N <= 100000。

代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[10000005];
int main(){
    cin>>n;
    a[1]=10;
    a[2]=20;
    for(int i=3;i<=n;i++)
    {
        if(i%2==1){
            a[i]=a[i-2]+1;
        }
        else{
            a[i]=a[i-2]-1;
        }
    }
    cout<<a[n];
    return 0;
}

数列二

琳琳刚学会使用数组,老师就给了他一个这样的问题:有两个数组 A[1..n]和 B[1..n]他们之间存在数学关系式是: B[i] = ( A[1] + A[2]+...A[i])/i(整除) ,其中 1 <= i <= n。

例如: A 数组是: 1, 3, 2, 6, 8。

那么 B 数组是:

微信截图_20221015133207.png

可以算出B数组是: 1,2,2,3,4 

输入格式

输入数据有两行:

第一行,一个整数 n。 1 <= n <= 100。

第二行,包含 n 个整数,第 i 个整数是 B[i]。 1 <= B[i] <= 10^9。

输出格式

输出数据仅一行,共 n 个整数,每个数之间用一个空格分开,第 i 个整数表示 A[i]。

数据保证 A[i]一定是整数,而且保证 1<=A[i]<=10^9。 

输入/输出例子1

输入:

4

3 2 3 5

输出:

3 1 5 11

代码:
#include<bits/stdc++.h>
using namespace std;
long long x,n,s;
int main(){
    cin>>n;
     for(int i=1;i<=n;i++)
     {
        cin>>x;
        cout<<x*i-s<<" ";
        s=i*x;
    }
    return 0;
}

斐波那契数列

斐波那契数列是非常出名的数列,它的公式是这样的:

1、 f[0] = 0;

2、 f[1] = 1;

3、 对于任意i>=2,都有f[i] = f[i-1] + f[i-2]。

于是,产生的斐波那契数列就是:0,1,1,2,3,5,8,13,21,34,......

现在给出一个正整数N,你要找出一个最小的整数X,同时满足如下两个条件:

1、 X >= 0。

2、 N+X是斐波那契数列中的某一个数,或者N-X是斐波那契数列中的某一个数。

请输出满足条件的最小的X。 

输入格式

一行,一个整数N。 1 <= N <= 1000000。 

输出格式

一个满足条件的最小的X。

输入/输出例子1

输入:

15

输出:

2

输入/输出例子2

输入:

19

输出:

2

输入/输出例子3

输入:

8

输出:

0

样例解释

样例1

因为15-2=13,而13是斐波那契数列的其中一个数。

样例2

因为19+2=21,而21是斐波那契数列的其中一个数。

样例3

因为8本身已经是斐波那契数列的一个数了。

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,a[1000005]={0,1,1},minx=0x3f3f3f3f3f3f3f3f;
int main(){
    cin>>n;
    for(int i=1;;i++)
    {
        if(i>=3)a[i]=a[i-1]+a[i-2];
        if(n==a[i])
        {
            cout<<0;
            return 0;
        }
        if(n>a[i])minx=min(minx,n-a[i]);
        if(a[i]>n)
        {
            if(a[i]-n>minx)break;
            else minx=min(minx,a[i]-n);
        }
    }
    cout<<minx;
    return 0;
}

前面几道题比较水,下面开始上难度了

铺地砖

一天,晨晨的数学老师布置了一道题目,大意如下:用1*1和2*2的瓷砖不重叠地铺满n*3的地板,共有多少种方案?

例如:

n=1时:1*3的地板方法就一个,直接由三个的瓷砖铺满。

n=2时:2*3的地板可以由下面3种方案铺满:

微信图片_20220123173528.png

输入格式

第一行:一个整数n(1<=n<=50)

输出格式

输出铺满n*3的地板的方案数

输入/输出例子1

输入:

3

输出:

5

数据范围

对于20%的数据,1<=n<=15;

对于50%的数据,1<=n<=30;

对于100%的数据,1<=n<=50;

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,f[100005];
int main(){
    cin>>n;
    f[0]=1;f[1]=1,f[2]=3; 
    for(int i=2;i<=n;i++)
        f[i]=f[i-1]+f[i-2]*2;
    cout<<f[n];
    return 0;

}

街道路径

设有一个N*M(1<=N<=50,1<=M<=50)的街道,规定行人从A(1,1)出发,在街道上只能向东或北行走。

2065.png

若在此街道中,设置一个矩形障碍区域(包括围住该区域的的街道)不让行人通行,如上图中用“*”表示的部分。此矩形障碍区域用2对顶点坐标给出,如上图中的2对顶点坐标为(2,2),(8,4),此时从A出发到达B的路径有两条。
现给出N、M,同时再给出此街道中的矩形障碍区域的2对顶点坐标(x1,y1),(x2,y2),请求出此时所有从A出发到达B的路径的条数。

输入格式

第一行输入n,m
第二行分别输入对应障碍的定点坐标x1,y1,x2,y2

输出格式

一行,即所有从A出发到达B的路径的条数

输入/输出例子1

输入:

9 5
2 2 8 4

输出:

2

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,m,x2,y2,a[105][105];
long long x,y;
int main(){
    cin>>n>>m>>x>>y>>x2>>y2;
    if(x>x2){
        swap(x,x2);
        swap(y,y2);
    }
    for(int i=x;i<=x2;i++){
        for(int j=y;j<=y2;j++)
            a[i][j]=-1;
    }
    a[1][1]=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i][1]!=-1)
            a[i][1]=1;
        else break;
    }
    for(int i=2;i<=m;i++)
    {
        if(a[1][i]!=-1)
            a[1][i]=1;
        else break;
    }
    for(int i=2;i<=n;i++){
        for(int j=2;j<=m;j++){
            if(a[i][j]!=-1){
                if(a[i-1][j]!=-1)a[i][j]+=a[i-1][j];
                if(a[i][j-1]!=-1)a[i][j]+=a[i][j-1];
            }
        }
    }
    cout<<a[n][m];
    return 0;
}

马拦过河卒简化版

棋盘上A点有一个过河卒,需要走到目标点。卒行走的规则:可以向下、或者向右。棋盘用坐标表示,那么从点(0,0)开始,每次只能向下走一步或者向右走一步,到达点(x,y)有多少种不同的走法?

输入格式

两个整数,即x和y。 0 <= x, y < = 10。

输出格式

一个整数,不同的走法的数量。

输入/输出例子1

输入:

1 1

输出:

2

代码:
#include<bits/stdc++.h>
using namespace std;
long long a[50][50];
long long x,y;
int main(){
    cin>>x>>y;
    for(int i=0;i<=x;i++)
        a[i][0]=1;
    for(int i=0;i<=y;i++)
        a[0][i]=1;
    for(int i=1;i<=x;i++)
        for(int j=1;j<=y;j++)
            a[i][j]=a[i-1][j]+a[i][j-1];
    cout<<a[x][y];
    return 0;
}

马拦过河卒

棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

1032.png

棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过15的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入格式

一行四个数据,分别表示B点坐标和马的坐标。

输出格式

一个数据,表示所有的路径条数。

输入/输出例子1

输入:

6 6 3 2

输出:

17

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,a[1005][1005]={0};
int main()
{
    a[0][0]=1;
    cin>>n>>m>>x>>y;
    for(int i=0;i<=n+1;i++)
    {
        for(int j=0;j<=m+1;j++)
        {
            if((i==0&&j==0)||(i==x&&j==y)||(i==x+1&&j==y+2)||(i==x+2&&j==y+1)||(i==x+2&&j==y-1)||(i==x+1&&j==y-2)||(i==x-1&&j==y+2)||(i==x-2&&j==y+1)||(i==x-1&&j==y-2)||(i==x-2&&j==y-1))continue;
            else
            {
                if(i==0&&j>0)a[i][j]=a[i][j-1];
                else if(i>0&&j==0)a[i][j]=a[i-1][j];
                else a[i][j]=a[i][j-1]+a[i-1][j];
            }
        }
    }
    cout<<a[n][m]<<endl;
    return 0;
}

再水几道其他类型的题

直方图的水量

给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图 能存多少水量? 直方图的柱状宽度为 1。 

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的直方图,在这种情况下,可以接 6 个单位的水(蓝色部分表示水)。

微信截图_20220527094751.png

输入格式

第 1 行:1 个正整数 N,不超过 10000。 

第 2 行:N 个整数,范围[0,100000]。

输出格式

输出一个整数。

输入/输出例子1

输入:

12

0 1 0 2 1 0 1 3 2 1 2 1

输出:

6

代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[100005],top;
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    for(int i=1;i<n;i++){
        if(a[i]>a[top]){
            top=i;
        }
    }
    int water=0;
    int h=0;
    for(int i=0;i<top;i++){
        if(h>a[i]){
            water+=h-a[i];
        }
        else{
            h=a[i];
        }
    }
    h=0;
    for(int i=n-1;i>=top;i--){
        if(h>a[i]){
            water+=h-a[i];
        }
        else{
            h=a[i];
        }
    }
    cout<<water;
    return 0;
}

乐乐的工作

乐乐非常喜欢现在这份工作,因为公司只要求员工把每天的工作完成,不要求固定的上班时间。假如乐乐的同事有的从300时刻(以秒为单位),一直工作到3000时刻(我们认为从300时刻工作到3000时刻所工作的时间为3000-300=2700秒,即结束的那个时刻是没有工作的);有的从700时刻开始,在5200时刻结束;有的从6500时刻开始,到8100时刻结束。那么期间最长的至少有一个人在工作的连续时间是4900秒(从300时刻到5200时刻),而最长的无人工作的连续时间为1300时刻(从5200时刻到6500时刻)。 
现在乐乐想知道从最早有人开始工作的时间至最后一个人离开的时间里,公司里最长至少有一人在工作的时间段和最长的无人工作的时间段。 

输入格式

第一行一个整数n(1<=n<=5000); 
接着有n行,每行有两个用空格分开的正整数Ai和Bi(0<=Ai、Bi<=1000000)。 

输出格式

一行,两个整数,即题目所要求的两个答案。

输入/输出例子1

输入:

3
300 3000
700 5200
6500 8100

输出:

4900 1300
代码:
#include<bits/stdc++.h>
using namespace std;
int n,x,y,a[1000001],maxtim,now,tot,max1,max0;
int main()
{
    scanf("%d",&n);
    while(n--){
        scanf("%d%d",&x,&y);
        a[x]++;
        a[y]--;
        maxtim=max(maxtim,y);
    }
    int i=0;
    while(!a[i])i++;
    now=a[i];
    i++;
    for(;i<=maxtim;i++){
        tot++;
        if(a[i]){
           if(now){
              if(!(now+a[i]))max1=max(max1,tot),tot=0;
              now+=a[i];
           }
           else max0=max(max0,tot),tot=0,now+=a[i];
        }
    }
    printf("%d %d\n",max1,max0);
    return 0;
}

安装饮水机

为倡导城市低碳生活,市文明办计划举办马拉松比赛,为确保比赛安全,沿途设置了一些观察点。每个观察点派一个观察员驻守。由于天气比较炎热,需要在沿途安装一些饮水机,使得观察员可以去取水喝。由于观察员每移动一个单位的路程,需要耗费一个单位的体力。而每个观察员的体力有限,只能在他体力能支持的范围内去取水喝,要不他就会渴死或累死。 
聪明的楠楠也参与了这次比赛的筹备工作。他的任务是设计一个理想的安装饮水机方案,使得安装的饮水机最少,但又保证所有观察员都能取到水喝。 

输入格式

输入数据有若干行。
第一行,仅一个整数,表示有N(n小于等于1000)个观察点。 
接下来有N行,每行两个整数Si(Si小于等于100000)和Wi(Wi小于等于50000),其中Si表示每个观察点到起点的路程,Wi表示该观察点中驻点观察员的体力。 

输出格式

输出最少要安装几台饮水机

输入/输出例子1

输入:


6 3 
12 2 
1 5 
14 5 

输出:

2

代码:
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
    int a, b;
}q[100005]; 
bool cmp(node x,node y)
{
    if(x.a+x.b!=y.a+y.b)return x.a+x.b<y.a+y.b;
    return x.a<y.a; 
}
bool check(int x)
{
    int num=x;
    int loc=0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        if(loc>q[i].a+q[i].b||loc<q[i].a-q[i].b) {
            num--;
            loc=q[i].a+q[i].b;
        }
        if(num<0)return true;
    }
    return false;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>q[i].a>>q[i].b;
    sort(q+1,q+1+n,cmp);
    int l=0,r=n;
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid))l=mid+1;
        else r=mid;
    }
    cout<<l;
    return 0;
}

种树

一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号为1..n。每个块的大小为一个单位尺寸并最多可种一棵树。每个居民想在门前种些树并指定了三个号码b,e,t。这三个数表示该居民想在b和e之间最少种t棵树。当然,b<=e,居民必须保证在指定地区不能种多于地区被分割成块数的树,即要求t<=e-b+1。允许居民想种树的各自区域可以交叉。出于资金短缺的原因,环保部门请你求出能够满足所有居民的要求,需要种树的最少数量。

输入格式

第一行为h,表示房子的数目; 

第二行为n,表示区域的个数; 

下面h行描述居民的需要:b e t (1<=b<=e<=30000,r<=e-b+1) 分别用一个空格分开。 

输出格式

输出为满足所有要求的最少树的数量。

输入/输出例子1

输入:

9
4
1 4 2
4 6 2
8 9 2
3 5 2

输出:

5

数据范围

30%的数据满足1<=n<=1000;1<=h<=500。
100%的数据满足n<=30000;h<=30000。

代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
    int l,r,sum;
}a[30005];
bool cmp(node a,node b)
{
    if(a.r==b.r)
		return a.l<b.l;
	return a.r<b.r;
}
int n,k,num,len[30005];
int main()
{
    cin>>n>>k;
    for(int i=1;i<=k;i++)
        cin>>a[i].l>>a[i].r>>a[i].sum;
    sort(a+1,a+1+k,cmp);
    for(int i=1;i<=k;i++)
	{
		int ans=0;
		for(int j=a[i].l;j<=a[i].r;j++)
			ans+=len[j];
		for(int j=a[i].r;j>=a[i].l&&ans<a[i].sum;j--)
			if(!len[j])len[j]=1,ans++,num++;
	}
    cout<<num;
    return 0;
}

菜鸟整理的一些题,大佬不喜勿喷......

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值