洛谷刷题周日版

今天主打一个递推主题

题1:台阶问题https://www.luogu.com.cn/problem/P1192

题目描述

有 �N 级台阶,你一开始在底部,每次可以向上迈 1∼�1∼K 级台阶,问到达第 �N 级台阶有多少种不同方式。

输入格式

两个正整数 �,�N,K。

输出格式

一个正整数 ���(mod100003)ans(mod100003),为到达第 �N 级台阶的不同方式数。

输入输出样例

输入 #1复制

5 2

输出 #1复制

8

说明/提示

  • 对于 20%20% 的数据,1≤�≤101≤N≤10,1≤�≤31≤K≤3;
  • 对于 40%40% 的数据,1≤�≤10001≤N≤1000;
  • 对于 100%100% 的数据,1≤�≤1000001≤N≤100000,1≤�≤1001≤K≤100。

思路:观察可以得到,当前的台阶数,可以在经过1——k阶的迈步得到,其次就是初始化

#include<bits/stdc++.h>
#include<math.h>
#include<vector>
using namespace std;
const int mod=100003;
int a[100005];
int main()
{
	int n,k;
	cin>>n>>k;
	a[0]=1,a[1]=1;
	for (int i=2;i<=n;++i)
	{
		for (int j=1;j<=k;++j)
		{
			if (i>=j)
			{
				a[i]=(a[i-j]+a[i])%mod;
			}
		}
	}
	cout<<a[n]%mod;
}

题2:素数方阵https://www.luogu.com.cn/problem/B3738

题目描述

把前 �2n2 个素数从左上角开始按右、下、左、上、右、下、左、上……的顺序填入 �×�n×n 的方阵就得到了蛇形素数方阵。以下是 �=4n=4 和 �=5n=5 的蛇形素数方阵:

给出 �n,你的任务是求出 �×�n×n 的蛇形素数方阵,并输出其中某个方格中的数值。

素数,又称质数,是指除 11 和其自身之外,没有其他约数的大于 11 的正整数。

输入格式

输入一行三个正整数 �,�,�n,x,y。

输出格式

输出一行一个整数,表示 �×�n×n 蛇形素数方阵第 �x 行第 �y 列中的数字。

输入输出样例

输入 #1复制

5 1 4

输出 #1复制

7

输入 #2复制

5 4 3

输出 #2复制

79

说明/提示

样例解释

参考上图 �=5n=5。

数据规模

所有数据满足 1≤�,�≤�≤201≤x,y≤n≤20。

思路:运用素数筛法,把需要的素数都得到,其次就是蛇形矩阵的问题,这个问题做过,具体就是通过设置四个方向,遇到阻碍的时候就换个方向

int dir[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
    int d = 0, x = 0, y = 0, idx = 2;
    for (int i = 0; i < n * n; ++i) {
        while (!isPrime[idx]) {
            ++idx;
        }
        b[x][y] = idx++;

        int tx = x + dir[d][0], ty = y + dir[d][1];
        if (tx < 0 || tx >= n || ty < 0 || ty >= n || b[tx][ty] != 0) {
            d = (d + 1) % 4;
        }
        x += dir[d][0];
        y += dir[d][1];
    }

具体就是这样实现的,上面的idx主要是用来找素数的,xy表示位置信息

#include<iostream>
#include<string>
#include <vector>
#include <algorithm>
#include<math.h>
#include<stack>//添加栈
#include<ctype.h>
#include<cstdlib>
#define pritnf printf
#define itn int
#define INF 10234567111
#define MAX 2000000
using namespace std;
#define  str  string 
#define  ll	  long long int 
//字符串类型是string     ceil()向上取整,C++的正常逻辑是向下取整
int main() {
    int n, x1, y1;
    cin >> n >> x1 >> y1;
    vector<bool> isPrime(10000000, true);
    isPrime[0] = isPrime[1] = false;
    for (int i = 2; i <= 10000; ++i) {
        if (isPrime[i]) {
            for (int j = i * i; j <= 10000; j += i) {
                isPrime[j] = false;
            }
        }
    }
    int b[21][21] = { 0 };
    int dir[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
    int d = 0, x = 0, y = 0, idx = 2;
    for (int i = 0; i < n * n; ++i) {
        while (!isPrime[idx]) {
            ++idx;
        }
        b[x][y] = idx++;

        int tx = x + dir[d][0], ty = y + dir[d][1];
        if (tx < 0 || tx >= n || ty < 0 || ty >= n || b[tx][ty] != 0) {
            d = (d + 1) % 4;
        }
        x += dir[d][0];
        y += dir[d][1];
    }

    cout << b[x1 - 1][y1 - 1] << endl;
    return 0;
}

完整代码如上

题3:独木桥https://www.luogu.com.cn/problem/P1007

题目背景

战争已经进入到紧要时间。你是运输小队长,正在率领运输部队向前线运送物资。运输任务像做题一样的无聊。你希望找些刺激,于是命令你的士兵们到前方的一座独木桥上欣赏风景,而你留在桥下欣赏士兵们。士兵们十分愤怒,因为这座独木桥十分狭窄,只能容纳 11 个人通过。假如有 22 个人相向而行在桥上相遇,那么他们 22 个人将无法绕过对方,只能有 11 个人回头下桥,让另一个人先通过。但是,可以有多个人同时呆在同一个位置。

题目描述

突然,你收到从指挥部发来的信息,敌军的轰炸机正朝着你所在的独木桥飞来!为了安全,你的部队必须撤下独木桥。独木桥的长度为 �L,士兵们只能呆在坐标为整数的地方。所有士兵的速度都为 11,但一个士兵某一时刻来到了坐标为 00 或 �+1L+1 的位置,他就离开了独木桥。

每个士兵都有一个初始面对的方向,他们会以匀速朝着这个方向行走,中途不会自己改变方向。但是,如果两个士兵面对面相遇,他们无法彼此通过对方,于是就分别转身,继续行走。转身不需要任何的时间。

由于先前的愤怒,你已不能控制你的士兵。甚至,你连每个士兵初始面对的方向都不知道。因此,你想要知道你的部队最少需要多少时间就可能全部撤离独木桥。另外,总部也在安排阻拦敌人的进攻,因此你还需要知道你的部队最多需要多少时间才能全部撤离独木桥。

输入格式

第一行共一个整数 �L,表示独木桥的长度。桥上的坐标为 1,2,⋯ ,�1,2,⋯,L。

第二行共一个整数 �N,表示初始时留在桥上的士兵数目。

第三行共有 �N 个整数,分别表示每个士兵的初始坐标。

输出格式

共一行,输出 22 个整数,分别表示部队撤离独木桥的最小时间和最大时间。22 个整数由一个空格符分开。

输入输出样例

输入 #1复制

4
2
1 3

输出 #1复制

2 4

说明/提示

对于 100%100% 的数据,满足初始时,没有两个士兵同在一个坐标,1≤�≤5×1031≤L≤5×103,0≤�≤5×1030≤N≤5×103,且数据保证 �≤�N≤L。

思路:最短时间,就是所有人中,到达两端最短时间的最大值,通俗的说,就是:一个人可以选择到达两端,这样就产生了两个时间,这两个时间有长有短,我们需要那个短的时间,最后我们在找到这个最短时间的最大值就是最短的时间,而所需要撤退的最大时间也是同样的方法,可以轻松的知道,这个时候是由两个端点的人产生,所有只需要比较端点的人到达的时间与另一个人比较就可以了。

#include<bits/stdc++.h>
using namespace std;
#define INF 10234567111
int main()
{
	int l;
	cin >> l;
	int n;
	cin >> n;
	if (!n)
	{
		cout<<"0 0";
		return 0;
	}
	int a[5005];
	for (int i = 0; i < n; ++i) cin >> a[i];
	int min_time,max_time;
	sort(a, a + n);
	for (int i=0;i<n;++i)
	{
		min_time=max(min(a[i],l+1-a[i]),min_time);
	}
	max_time=max(l+1-a[0],a[n-1]);
	cout<<min_time<<" "<<max_time;
}

题4:P1464 Functionhttps://www.luogu.com.cn/problem/P1464

题目描述

对于一个递归函数 �(�,�,�)w(a,b,c)

  • 如果 �≤0a≤0 或 �≤0b≤0 或 �≤0c≤0 就返回值11。
  • 如果 �>20a>20 或 �>20b>20 或 �>20c>20 就返回 �(20,20,20)w(20,20,20)
  • 如果 �<�a<b 并且 �<�b<c 就返回�(�,�,�−1)+�(�,�−1,�−1)−�(�,�−1,�)w(a,b,c−1)+w(a,b−1,c−1)−w(a,b−1,c)。
  • 其它的情况就返回 �(�−1,�,�)+�(�−1,�−1,�)+�(�−1,�,�−1)−�(�−1,�−1,�−1)w(a−1,b,c)+w(a−1,b−1,c)+w(a−1,b,c−1)−w(a−1,b−1,c−1)

这是个简单的递归函数,但实现起来可能会有些问题。当 �,�,�a,b,c 均为 1515 时,调用的次数将非常的多。你要想个办法才行。

注意:例如 �(30,−1,0)w(30,−1,0) 又满足条件 11 又满足条件 22,请按照最上面的条件来算,答案为 11。

输入格式

会有若干行。

并以 −1,−1,−1−1,−1,−1 结束。

输出格式

输出若干行,每一行格式:

w(a, b, c) = ans

注意空格。

输入输出样例

输入 #1复制

1 1 1
2 2 2
-1 -1 -1

输出 #1复制

w(1, 1, 1) = 2
w(2, 2, 2) = 4

说明/提示

数据规模与约定

保证输入的数在 [−9223372036854775808,9223372036854775807][−9223372036854775808,9223372036854775807] 之间,并且是整数。

保证不包括 −1,−1,−1−1,−1,−1 的输入行数 �T 满足 1≤�≤1051≤T≤105。

思路:这道题由于递归的原因,时间效率比较低,所有用记忆化搜索找,然后按照题目所给的信息走一遍就AC了。

#include<bits/stdc++.h>
using namespace std;
long long dp[25][25][25];
long long  w(long long  a,long long  b,long long  c)
{
	
	if (a<=0 || b<=0 || c<=0 ) return 1;
	if (a>20 || b>20 || c>20 ) return w(20,20,20);
	if (dp[a][b][c]!=0) return dp[a][b][c];
	if (a<b && b<c)
	{
		if (dp[a][b][c-1]==0)
		{
			dp[a][b][c-1]=w(a,b,c-1);
		}
		if (dp[a][b-1][c-1]==0)
		{
			dp[a][b-1][c-1]=w(a,b-1,c-1);
		}
		if (dp[a][b-1][c]==0)
		{
			dp[a][b-1][c]=w(a,b-1,c);
		}
		dp[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
	}
	else 
	{
		if (dp[a-1][b][c]==0)
		{
			dp[a-1][b][c]=w(a-1,b,c);
		}
		if (dp[a-1][b-1][c]==0)
		{
			dp[a-1][b-1][c]=w(a-1,b-1,c);
		}
		if (dp[a-1][b-1][c-1]==0)
		{
			dp[a-1][b-1][c-1]==w(a-1,b-1,c-1);
		}
		dp[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
	}
	return dp[a][b][c];
}
int main()
{
	long long  a,b,c;
	while (~scanf("%lld %lld %lld",&a,&b,&c))
	{
		if (a==-1 && b==-1 && c==-1)
		{
			return 0;
		}
		printf("w(%lld, %lld, %lld) = ", a, b, c);
		printf("%lld\n", w(a, b, c));
	}
}

题5:P2437 蜜蜂路线https://www.luogu.com.cn/problem/solution/P2437

题目描述

一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:蜜蜂从蜂房 �m 开始爬到蜂房 �n,�<�m<n,有多少种爬行路线?(备注:题面有误,右上角应为 �−1n−1)

输入格式

输入 �,�m,n 的值

输出格式

爬行有多少种路线

输入输出样例

输入 #1复制

1 14

输出 #1复制

377

说明/提示

对于100%的数据,1≤�,�≤10001≤M,N≤1000

思路:一道高精度,与之前刷的数楼梯相似https://www.luogu.com.cn/problem/P1255

当前的蜂房数字,由前两次得到(类似于斐波那契数列),区别就在于把递推的过程由高精度的方式实现,这个方法还是比较好,可以学习,定义的二维数组,前一个是当前的蜂房,后一个是当前蜂房的位数

#include<bits/stdc++.h>
using namespace std;
#define itn int 
int f[1500][1500];
int len=1;
void zhuanyi(int x)
{
	for (int i=1;i<=len;++i)
	{
		f[x][i]=f[x-1][i]+f[x-2][i];
	}
	for (itn i=1;i<=len;++i)
	{
		if (f[x][i]>=10)
		{
			f[x][i+1]+=f[x][i]/10;
			f[x][i]%=10;
		}
	}
	if (f[x][len+1])len++;
}
int main()
{
	itn n,m;
	cin>>n>>m;
	f[1][1]=1,f[2][1]=2;
	for (int i=3;i<=m-n;++i) zhuanyi(i);
	for (int i=len;i;--i)cout<<f[m-n][i];
}
  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值