第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(自测)

做对了1 2 3 4 8题,共得60分
其中第9题运行超时,得10分
用时两个半小时

1、5 进制转换
2 日期
3 简单数学
4 简单数学,找规律
6 二维前缀和,双指针
7 未看
8 简单搜索
9 dfs+dp+剪枝(记忆型dfs)
10 未看

九进制转十进制

问题描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
九进制正整数 ( 2022 ) 9 (2022)_9 (2022)9​ 转换成十进制等于多少?

很简单的一题

#include <iostream>
using namespace std;
int main()
{
  // 请在此输入您的代码
  cout << 1478;
  return 0;
}

顺子日期

问题描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。小明想知道在整个 2022 年份中,一共有多少个顺子日期?

1230
1231
1123
1012
0120,0121,0122,0123…(10个)

#include <iostream>
using namespace std;
int main()
{
  // 请在此输入您的代码
  cout << 14;
  return 0;
}

刷题统计

问题描述

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做a道题目, 周六和周日每天做b道题目。请你帮小明计算, 按照计划他将在第几天实现做题数大于等于n题?

输入格式

输入一行包含三个整数 a,b和 n.

输出格式

输出一个整数代表天数。

样例输入

10 20 99

样例输出

8

评测用例规模与约定

对于 50 50% 50 的评测用例, 1 ≤ a , b , n ≤ 1 0 6 1≤a,b,n≤10^6 1a,b,n106

对于 100 100% 100 的评测用例, 1 ≤ a , b , n ≤ 1 0 18 1≤a,b,n≤10^{18} 1a,b,n1018

#include<iostream>
using namespace std;
typedef long long ll;

ll a, b, n;

int main()
{
	cin >> a >> b >> n;
	
	ll week = a * 5 + b * 2;
	ll t = n / week;//t个完整的周
	
	ll sum = t * week;//实际t周做的量
	t *= 7;
	
	for (int i = 1; i <= 7; i ++)
	{
		if (sum < n)
		{
			if (i <= 5) sum += a;//周一到五
			else sum += b;//周末
			t ++;//加一天
		}	
	}

	cout << t;
	return 0;
}

先直接算出需要多少个完整的一周

修剪灌木

问题描述

爱丽丝要完成一项修剪灌木的工作。

有N棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晩会修剪一棵灌 木, 让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后, 她会调转方向, 下一天开 始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。

灌木每天从早上到傍晩会长高 1 厘米, 而其余时间不会长高。在第一天的 早晨, 所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

输入格式

一个正整数 NN, 含义如题面所述。

输出格式

输出 NN 行, 每行一个整数, 第 ii 行表示从左到右第 ii 棵树最高能长到多高。

样例输入

3

样例输出

4
2
4

评测用例规模与约定

对于 30 30% 30 的数据, N ≤ 10 N≤10 N10.

对于 100 100% 100的数据, 1 < N ≤ 10000 1<N≤10000 1<N10000

#include<iostream>
using namespace std;

int n;

int h[10010];

int main()
{
	cin >> n;
	int t = (n+1)/2;
	
	for (int i = 1; i <= t; i ++)
	{
		h[i] = (n-i) * 2;
	}
	
	for (int i = t + 1; i <= n; i ++)
		h[i] = h[n-i+1];
	
	for (int i = 1; i <= n; i ++)
		cout << h[i] << endl;
		
	return 0;
}

找规律
比如是4棵树,砍树顺序如下:(每一列对应一棵树)
1 2 3 4
7 6 5 **
**8 9 10
第一次砍第1棵树是(1),第二次砍是(7),在这一段时间里第1棵树可以长到6
第一次砍第2棵树是(2),第二次砍是(6),在这一段时间里第1棵树可以长到4
再找规律可以发现每一棵树的最高高度是对称的
第3棵树最高4,第4棵树最高6

比如是5棵树,砍树顺序如下:(每一列对应一棵树)
1 2 3 4 5
9 8 7 6 **
**10 11 12 13
第一次砍第1棵树是(1),第二次砍是(9),在这一段时间里第1棵树可以长到8
第一次砍第2棵树是(2),第二次砍是(8),在这一段时间里第1棵树可以长到6
再找规律可以发现每一棵树的最高高度是对称的
第3棵树最高4,第4棵树最高6,第5棵树最高8

就可以找出规律:在前一半树中
第i棵树最高:(n-i)*2;

X 进制减法

问题描述

进制规定了数字在数位上逢几进一。

X 进制是一种很神奇的进制, 因为其每一数位的进制并不固定!例如说某 种 X 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 X 进制数 321 转换为十进制数为 65 。

现在有两个 X 进制表示的整数 A 和 B, 但是其具体每一数位的进制还不确 定, 只知道 A 和 B 是同一进制规则, 且每一数位最高为 N 进制, 最低为二进 制。请你算出 A−B 的结果最小可能是多少。

请注意, 你需要保证 A 和 B 在 X 进制下都是合法的, 即每一数位上的数 字要小于其进制。

输入格式

第一行一个正整数 N, 含义如题面所述。

第二行一个正整数 Ma​, 表示 X 进制数 A 的位数。

第三行 Ma​ 个用空格分开的整数, 表示 X 进制数 A 按从高位到低位顺序各 个数位上的数字在十进制下的表示。

第四行一个正整数 Mb​, 表示 X 进制数 B 的位数。

第五行 Mb个用空格分开的整数, 表示 X 进制数 B 按从高位到低位顺序各 个数位上的数字在十进制下的表示。

请注意, 输入中的所有数字都是十进制的。

输出格式

输出一行一个整数, 表示 X 进制数 A−B 的结果的最小可能值转换为十进 制后再模 1000000007 的结果。

样例输入

11
3
10 4 0
3
1 2 0

样例输出

94

样例说明

当进制为: 最低位 2 进制, 第二数位 5 进制, 第三数位 11 进制时, 减法 得到的差最小。此时 A 在十进制下是 108,B在十进制下是 14 , 差值是 94。

#include<iostream>
#include<cstdio>
typedef long long ll;
using namespace std;

const int N = 100010;
const int MOD = 1000000007;
int n, ma,mb;
int a[N], b[N];
int mx[N];
int ans[N];

int main()
{
    cin >> n;
    cin >> ma;
    for (int i = 0; i < ma; i ++) cin >> a[i];
    cin >> mb;
    for (int i = ma-mb; i < ma; i ++) cin >> b[i];
    
    for (int i = 0; i < ma; i ++)
    {
            mx[i] = max(a[i],b[i]) + 1; //当前最低进制
            if (mx[i] < 2) mx[i] = 2;
    }
        
    
    for (int i = ma-1; i >= 0; i --)
    {
        if (a[i] >= b[i]) ans[i] = a[i] - b[i];
        else{
            a[i] += mx[i];
            a[i+1] --;//借一位 
            ans[i] = a[i] - b[i];
        } 
    }
    
    int res = ans[0];
    for (int i = 1; i < ma; i ++)
        res = (((ll)mx[i] * res)%MOD + (ll)ans[i]) %MOD;
        
    cout << res;
    return 0;
}

减法那块想错了,想着可能减法中,a>b就要借位。。其实不用,减法都可以直接减得了

#include<iostream>
#include<cstdio>
typedef long long ll;
using namespace std;

const int N = 100010;
const ll MOD = 1000000007;
int n, ma,mb;
int a[N], b[N];
int mx[N];
ll ans[N];

int main()
{
	cin >> n;
	cin >> ma;
	for (int i = 0; i < ma; i ++) cin >> a[i];
	cin >> mb;
	for (int i = ma-mb; i < ma; i ++) cin >> b[i];
	
	for (int i = 0; i < ma; i ++)
	{
			mx[i] = max(a[i],b[i]) + 1; //当前最低进制
			if (mx[i] < 2) mx[i] = 2;
	}
		
	
	for (int i = ma-1; i >= 0; i --)
	{
		ans[i] = a[i] - b[i];
//		else{
//			a[i] += mx[i];
//			a[i+1] --;//借一位 
//			ans[i] = a[i] - b[i];
//		} 
	}
	
	ll res = ans[0];
	for (int i = 1; i < ma; i ++)
		res = (((ll)mx[i] * res)%MOD + (ll)ans[i]) %MOD;
		
	cout << res;
	return 0;
}

统计子矩阵

问题描述

给定一个 N×M 的矩阵 A, 请你统计有多少个子矩阵 (最小 1×1, 最大 N×M)满足子矩阵中所有数的和不超过给定的整数 K ?

输入格式

第一行包含三个整数 N,M,K.

之后 N 行每行包含 M 个整数, 代表矩阵 A.

输出格式

一个整数代表答案。

样例输入

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

样例输出

19

#include<iostream>
using namespace std;
typedef long long ll;

const int N = 55;
int n, m, k;
int a[N][N];
ll f[N][N];


int main()
{
    cin >> n>> m >> k;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            cin >> a[i][j];
            
    for (int j = 1; j <= m; j ++)
        for (int i = 1; i <= n; i ++)
            f[i][j] = f[i-1][j] + a[i][j];
    
    int res = 0;
    for (int i = 1; i <= n; i ++)
        for (int j = i; j <= n; j ++)
        {
            for (int l = 1,r = 1;l <= m; l ++)
            {
                ll sum = f[j][l] - f[i-1][l];
                while (r <= m && sum <= k)
                {
                    r ++;
                    sum += f[j][r] - f[i-1][r];
                }
                if (r > l)
                    res += (r - l);
            }
        }
    
    cout << res;
    return 0;
}

主要是 ll sum = f[j][l] - f[i-1][l];写错了,他计算的值是要一直用下去的。。

并且还有很多小错误,,,,
最后一个错误是看错了N的数据范围。。。

  • 改过的
#include<iostream>
using namespace std;
typedef long long ll;

const int N = 505;
int n, m;
ll k;
int a[N][N];
int f[N][N];


int main()
{
	cin >> n>> m >> k;
	for (int i = 1; i <= n; i ++)
		for (int j = 1; j <= m; j ++)
			cin >> a[i][j];
			
	for (int j = 1; j <= m; j ++)
		for (int i = 1; i <= n; i ++)
			f[i][j] = f[i-1][j] + a[i][j];
	
	ll res = 0;
	for (int i = 1; i <= n; i ++)
		for (int j = i; j <= n; j ++)
		{
			ll sum = f[j][1] - f[i-1][1];
			for (int l = 1,r = 1;l <= m; l ++)
			{
				while (r <= m && sum <= k)
				{
					r ++;
					sum += f[j][r] - f[i-1][r];
				}
				res += (r - l);
				sum -= f[j][l] - f[i-1][l];
			}
		}
	
	cout << res;
	return 0;
}

扫雷

题目描述

在一个 n 行 m 列的方格图上有一些位置有地雷,另外一些位置为空。

请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。

输入描述

输入的第一行包含两个整数 n,m。

第 2 行到第 n+1 行每行包含 m 个整数,相邻整数之间用一个空格分隔。如果对应的整数为 0,表示这一格没有地雷。如果对应的整数为 1,表示这一格有地雷。

其中,1≤n,m≤100 分钟后还是在当天。

输出描述

输出 n 行,每行 m 个整数,相邻整数之间用空格分隔。

对于没有地雷的方格,输出这格周围的地雷数量。对于有地雷的方格,输出 9。

输入输出样例

示例 1

输入

3 4
0 1 0 0
1 0 1 0
0 0 1 0

输出

2 9 2 1
9 4 9 2
1 3 9 2

#include<iostream>

using namespace std;

int n, m;
int a[105][105];
int dx[10] = {0,-1,-1,-1,0,1,1,1};
int dy[10] = {-1,-1,0,1,1,1,0,-1};
 
int main()
{
	cin >> n >> m;
	
	for (int i = 1; i <= n; i ++)
		for (int j = 1; j <= m; j ++)
		{
			int q;
			cin >> q;
			if (q == 1)	a[i][j] = 9;
			else a[i][j] = 0;
		}	
	
	for (int i = 1; i <= n; i ++)
		for (int j = 1;j <= m; j ++)
		{
			if (a[i][j] == 9) continue;
			for (int k = 0; k < 8; k ++)
			{
				if (a[i+dx[k]][j+dy[k]] == 9)
					a[i][j] ++;
			}
		}
	
	for (int i = 1; i <= n; i ++)
	{
		for (int j = 1;j <= m; j ++)
			cout << a[i][j] << ' ';
		cout << '\n';
	}	
	
	return 0;
}

李白打酒加强版

问题描述

话说大诗人李白, 一生好饮。幸好他从不开车。

一天, 他提着酒显, 从家里出来, 酒显中有酒 2 斗。他边走边唱:

无事街上走,提显去打酒。 逢店加一倍, 遇花喝一斗。

这一路上, 他一共遇到店 NN 次, 遇到花 MM 次。已知最后一次遇到的是花, 他正好把酒喝光了。

请你计算李白这一路遇到店和花的顺序, 有多少种不同的可能?

注意: 显里没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。

输入格式

第一行包含两个整数 N 和 M.

输出格式

输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果.

样例输入

5 10

样例输出

14

  • 暴力做法,只用了dfs(拿了10分)
#include<iostream>

using namespace std;
const int MOD = 1000000007;

int n, m;
int res;

void dfs(int x)
{
	if (x == 1 && n == 0 && m == 1)
	{
		res = res%MOD + 1;
		return;
	}//else if (x < 2) return; 
	
	for (int i = 0; i < 2; i ++)
	{
		if (i == 0 && n > 0 && x > 0)
		{
			n --;
			dfs(x*2);
			n ++;
		}else if (i == 1 && m > 1)
		{
			if (x == 0) return; //不合法 
			else
			{
				m --;
				dfs(x-1);
				m ++;	
			} 
		}
	}
	return ;
}
int main()
{
	cin >> n >> m;
	
	dfs(2);
	
	cout << res%MOD;
	
	return 0;
}
  • 看了别人的题解:dfs+dp(记忆型搜索)
#include<iostream>
#include<cstring>

using namespace std;
const int MOD = 1000000007;

int n, m;
int res;
int dp[110][110][110];

int dfs(int x, int nn, int mm)
{
	if (x <0 || nn < 0 || mm < 0) return 0;
	if (x > mm) return 0; 
	if (x == 1 && nn == 0 && mm == 1)
		return 1;
	
	if(dp[x][nn][mm] != -1) return dp[x][nn][mm];
	
	else return dp[x][nn][mm] = (dfs(x*2, nn-1, mm)+dfs(x-1,nn,mm-1)) % MOD;
}
int main()
{
	cin >> n >> m;
	memset(dp, -1, sizeof dp);
	
	cout << dfs(2, n, m);
	
	return 0;
}
  • 35
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

o_o O

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值