当前位置: 首页 > article >正文

第十六届蓝桥杯模拟赛(第一期)(C语言)

判断质因数

如果一个数p是个质数,同时又是整数a的约数,则p称为a的一个质因数。
请问2024有多少个质因数。

  • 了解
    • 约数,又称因数。整数a整除整数b,b为a的因数(约数)
    • 质数,又称素数。只有1和它本身两个因数,即只能被1和它本身整除
  • 考察:循环枚举2024的每一个因数,并且判断是否为质数 

思路

使用平方根判断法(判断是否为质数) 

  • 因为 n = a * b,这两个都为 x 的因数
  • 当 a < sqrt(n) 时,则有 b * a = n(b > sqrt(n))
  • 当 a >= sqrt(n) 时,则有 b * a = n (b <= sqrt(n))
  • 所以判断时,变量 i 从 2 开始 只需要循环到 sqrt(n) 即可

代码

#include <bits/stdc++.h> 
// 判断是否为质数

// 平方根判断法
//check,检查是否为质数 
int chk(int x)  {
	for(int i = 2; i <= sqrt(x); ++i)  {
		if (x % i == 0)  {
			return 0; 
		}
	}
	return 1; 
}



int main() {
	int ans = 0;
	// 检查是否为因数 
	for (int i = 2; i < 2024; ++i) {
		if (2024 % i == 0) ans += chk(i); 
	}
	printf("%d\n", ans); 
	return 0; 
}

答案

3

分析

通过检查2024的所有可能的因数,然后判断这些因数是否为质数,来找出2024的所有质因数


	for (int i = 2; i < 2024; ++i) {
		if (2024 % i == 0) ans += chk(i); 
	}
  •  检查 i 是否为 2024 的因数,如果 i 能被 2024 整除,就是

int chk(int x)  {
	for(int i = 2; i <= sqrt(x); ++i)  {
		if (x % i == 0)  {
			return 0; 
		}
	}
	return 1; 
}
  • 当 x 不为素数,return 0; 连同 for 循环停止,继续对下一个 2024 的因数判断
  • 当 x 为素数,循环一直通过,直到结束,return 1;

开根次方

对于一个整数 n,我们定义一次开根变换会将 n 变为开根号后的整数部分,即变为平方和不超过 n 的数中的最大数
例如,20 经过开根后变为 4,如果再经过一次开根变换将变为 2,如果再经过一次开根变换将变为 1
请问,2024 经过多少次开根变换后会变为 1

  • 考察:循环、模拟、整数截断 

思路 

  • 用一个变量记录开了几次根,用强制类型转换把进行整数截断

代码

#include <bits/stdc++.h> 
int main() {
	int n = 2024;
	int ans = 0; 
	
	while (n > 1) {
		ans++;
		n = int(sqrt(n)); 
	}
	printf("%d\n", ans);
	 
	return 0; 
}

答案

4

补立方体

小蓝有很多 1x1x1 的小立方体,他可以使用多个立方体拼成更大的立方体。

例如,小蓝可以使用 8 个小立方体拼成一个大立方体,每边都是 2 个。

又如,小蓝可以使用 27 个小立方体拼成一个大立方体,每边都是 3 个。

现在,小蓝有 2024 个小立方体,他想再购买一些小立方体,用于拼一个超大的立方体,要求所有的小立方体都用上,拼成的大立方体每边长度都相等。

请问,小蓝最少需要购买多少个小立方体?

思路

  • 找到一个数的立方,大于等于 2024
  • 然后这个立方数减去 2024,就是还缺少的小立方体数

代码

#include <bits/stdc++.h> 

int main() {
	int n = 2024;
	
	for (int i = 1; ; ++i) {
		if (i*i*i >= n) {
			printf("%d\n", i*i*i - n) ; 
			return 0; 
		}
	}
	return 0; 
}

答案

173

一好日期 

如果一个日期的日期以 1 结尾(1日、11日、21日、31日)且为星期一,则称这个日期为一好日期。

请问从 1901 年 1 月 1 日至 2024 年 12 月 31 日总共有多少个一好日期。

提示:1901 年 1 月 1 日是星期二、

  • 考察:循环,模拟,闰年的判断方法

思路

  • 枚举年月日,判断星期

判断星期

  • 一星期 7 天,对 7 进行取余
  • 如果余 1,则为星期一
  • ……
  • 如果余 0,则为星期天
week = (week + 1) % 7;

判断闰年

  • 能被4整除而不能被100整除,或者能被400整除的年份都是闰年 

 代码 

#include <bits/stdc++.h> 

int main() {
	// 平年12个月,每月有多少天 
	int day_12_months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int week = 2;
	int ans = 0;
	
	// 对年进行循环 
	for (int year = 1901; year <= 2024; ++year) {
		// 对月进行循环,考虑2月 
		for (int month = 1; month <= 12; ++month) {
			int day_1_month = day_12_months[month - 1]; // 具体某一月的天数
			
			// 如果是闰年的2月,天数+1 
			if ((month == 2) && 
			((year % 4 == 0 && year % 400 != 0) || year % 400 == 0))
				day_1_month++;
			
			// 对天进行循环	
			for (int day = 1; day <= day_1_month; ++day) {
				if (day % 10 == 1 && week == 1) { // 判断一好日期 
					ans++; 
				}
				week = (week + 1) % 7; // 判断星期 
			}	 
		} 
	}
	printf("%d\n", ans) ; 
	return 0; 
}

答案

762

特殊的V

两个数按位异或是指将这两个数转换成二进制后,最低位与最低位异或作为结果的最低位,次低位与次低位异或作为结果的次低位,以此类推。

例如,3 与 5 按位异或值为 6 。

小蓝有以下 30 个整数:

9226, 4690, 4873, 1285, 4624, 1596, 6982, 590, 8806, 121, 8399, 8526, 5426, 64, 9655, 7705, 3929, 3588, 7397, 8020, 1311, 5676, 3469, 2325, 1226, 8203, 9524, 3648, 5278, 8647

小蓝想找一个整数 V ,使得 V 与这 30 个数分别异或后,得到的 30 个数的平方和最小。请问平方和最小是多少? 

  • 考察位运算

思路 

异或操作符(xor) ^

  • 以两进制表示数字,通过异或操作符,二进制位上,相同为 0,不同为 1

  • 最大值是9665没有超过15位,所以我们可以枚举到2¹⁵即可
    • 计算器 9665 的二进制为 0010 0101 1100 0001
  • 用 i 进行遍历,上限是 2¹⁵,用左移操作符,1 << 15表示
    • 1 的二进制数为 0001,末位的 1 向左移 15 位

代码

#include <stdio.h> 

int a[] = {9226, 4690, 4873, 1285, 4624, 1596, 6982, 590, 8806, 
121, 8399, 8526, 5426, 64, 9655, 7705, 3929, 3588, 7397, 8020,
1311, 5676, 3469, 2325, 1226, 8203, 9524, 3648, 5278, 8647}; 

int main() {
	// 赋值一个绝对比答案大的数
	long long ans = 1000000000000000000LL; 
	
	// 1左移15位就是2的15次
	for (int i = 0; i < (1 << 15); ++i) {
		long long tmp = 0; 
		for (int j = 0; j < 30; ++j) {
			tmp += (a[j] ^ i) * (a[j] ^ i); 
		}
		ans = ans > tmp ? tmp : ans ; 
	}
	printf("%lld", ans); 
	return 0; 
}

答案

1070293541

停车收费 

  • 考察:模拟、整除 

【问题描述】
小蓝在一个停车场停车。

停车场的收费规则为:每 15 分钟收费 2 元,不满 15 分钟的不收费。

小蓝总共停车 n 分钟,请问收费总额是多少?

【输入格式】
输入一行包含一个整数 n ,表示小蓝停车的时长。

【输出格式】
输出一行包含一个整数,表示停车费用。

【样例输入】
150

【样例输出】
20

【样例输入】
2024

【样例输出】
268

【评测用例规模与约定】
对于所有评测用例,1 <= n <= 10000。

思路

  • 求 n 分钟里包含多少 15 分钟

代码 

#include <stdio.h> 
#include <math.h> 

int main() {
	int n;
	scanf("%d", &n);
	printf("%d\n", n / 15 * 2); 
	return 0; 
}

数位减法

  • 考察:思维、整数分解、循环

小蓝有一个整数 n ,每次操作,可以将这个整数的每个非零数位减少 1 。

请问经过多少次操作,这个数会变为 0 。

例如,整数 2024 经过一次操作变为 1013,再经过一次操作变为 2 (即0002),再经过两次操作变为 0 ,总共经过 4 次变换变为 0 。

【输入格式】
输入一行包含一个整数 n 。

【输出格式】
输出一行,包含一个整数,表示答案。

【样例输入】
2024

【样例输出】
4

【评测用例规模与约定】
对于 50% 评测用例,1 <= n < 10000

对于所有评测用例,1 <= n < 1000000000

思路 

  • 答案就是数位中的最大值

代码 

#include <stdio.h> 

int main() {
	int n; 
	int ans = 0;
	
	scanf("%d", &n);
	
	while(n > 0) {
		int tmp = n % 10;
		n /= 10;
		ans = ans < tmp ? tmp : ans; 
	}
	printf("%d\n", ans); 
	return 0; 
}

指数计算 

  • 考察:模拟、取模、循环

输入 n,请计算 n 的 n 次方。答案可能很大,请输出答案除以 2024 的余数

【输入格式】

输入一行包含一个整数 n 

【输出格式】

输出一行,包含一个整数,表示 n 的 n 次方除以 2024 的余数

【样例输入】

10

【样例输出】

936

【评测用例规模与约定】

对于 20% 的评测用例,1 <= n <= 10

对于 60% 的评测用例,1 <= n <= 100

对于所有评测用例,1 <= n <= 1000000 

思路

  • 不断地对 ans 乘以 n,乘以 n 次
  • 要一边乘,一边取模
    • long long 最大 2⁶⁴  左右,也就是 10¹⁸ ~ 10¹⁹ 左右,而评测用例中,如过 n = 1000000,3次左右就到上限了,所以不能直接 n * n
  • 使用快速幂和整数取模的性质关于取模和快速幂的笔记

代码

#include <stdio.h>

// 快速幂算法
long long fastPower(long long base, long long exponent, long long mod) {
    long long ans = 1;
    base = base % mod;
    while (exponent > 0) {
        if (exponent & 1) {
            ans = (ans * base) % mod;
        }
        exponent = exponent >> 1;
        base = (base * base) % mod;
    }
    return ans;
}

int main() {
    long long n;
    scanf("%lld", &n);
    printf("%lld\n", fastPower(n, n, 2024));
    return 0;
}

减法求值

小蓝有一个减法式子,形如 a-b,其中 a 和 b 都是非负整数(不保证结果非负)。

请编程处理这个式子,输出运算结果。

【输入格式】
输入一行包含一个减法表达式,式子中仅含数字字符和一个减号。

【输出格式】
输出一行包含一个整数,表示运算结果。

【样例输入】
2024-1949

【样例输出】
75

【样例输入】
20-24

【样例输出】
-4

【评测用例规模与约定】
对于 50% 的评测用例,减法中的两个数都是不超过 10000 的非负整数。

对于所有评测用例,减法中的两个数都是不超过 1000000000 的非负整数。

代码 

#include <stdio.h> 

int main() {
	int a, b;
	scanf("%d-%d", &a, &b) ;
	printf("%d\n", a-b); 
}

 间隔最大

  • 考察前缀和,分类讨论
  • 将偶数和奇数分开考虑
  • 对奇数和偶数分别使用前缀和预处理,在获取某个长度为 k 的子段时,直接利用前缀和处理即可
  •  

小蓝有一个长度为 n 的整数数列 a[1], a[2], ..., a[n] 。

对于一个给定的整数 k ,小蓝想找到相邻间隔为 1 的 k 个数 a[p], a[p+2], a[p+4], ..., a[p+2k-2],使得他们的和最大。其中 1 <= p <= n-2k+2。

给定数列和 k ,请问给出最大的和。

【输入格式】
输入的第一行包含一个整数 n 。

第二行包含 n 个整数,相邻数之间使用一个空格分隔,依次表示 a[1], a[2], ..., a[n] 。

第三行包含一个整数 k 。

【输出格式】
输出一行,包含一个整数,表示答案。

【样例输入】

10
2 1 4 7 4 8 3 6 4 7
2

【样例输出】

15

【样例说明】
取 p=4,a[4]+a[6]=7+8=15 最大。

【评测用例规模与约定】
对于 30% 的评测用例,1 <= k <= n <= 100 , 1 <= a[i] <= 10000 。

对于 60% 的评测用例,1 <= k <= n <= 3000 , 1 <= a[i] <= 10000 。

对于所有评测用例,1 <= k <= n <= 100000 , 1 <= a[i] <= 1000000 。

思路

  • 首先求出从数组下标1开始,往后k个奇数下标位置的和与偶数下标位置的和。

  • 接着以长度为k个数,向后滑动,每移动一个,让和减去最前面的数,加上最后面的新进来的数。

变成了求连续的 k 个数的和 -> 前缀和

代码 

#include <stdio.h> 
#include <math.h> 
#define N 100000

long long odd[N + 1], even[N + 1];
 
int main() {
	int n;
	scanf("%d", &n);
	int oddn = 0, evenn = 0; // 奇数位置的个数,偶数位置的个数
	long long ans = 0; 
	for (int i = 1; i <= n; ++i) {
		if (i % 2 == 1) {
			oddn++;
			scanf("%lld", &odd[oddn]);
			odd[oddn] += odd[oddn - 1]; // 奇数的前缀和 
		} else {
			evenn++;
			scanf("%lld", &even[evenn]);
			even[evenn] += even[evenn - 1]; //偶数的前缀和 
		} 
	}
	
	int k;
	scanf("%d", &k);
	for (int i =k; i <= oddn; ++i) { // 处理奇数 
		if (odd[i] - odd[i - k] > ans) {
			ans = odd[i] - odd[i - k] ; 
		}
	}
	
	for (int i = k; i <= evenn; ++i) { // 处理偶数 
		if (even[i] - even[i - k] > ans) {
			ans = even[i] - even[i - k]; 
		}
	}
	
	printf("%lld", ans); 
	return 0; 
}

分析 

  1. 理解问题:我们需要找到一种方式来最大化间隔为 1 的 k 个数的和。这意味着我们需要考虑两种情况:一种是从奇数位置开始取数,另一种是从偶数位置开始取数。

  2. 前缀和:为了快速计算任意区间的和,我们可以使用前缀和。前缀和是一种数据结构,它允许我们在 O(1) 时间内计算任意区间的和。对于奇数位置和偶数位置的数,我们分别计算它们的前缀和。

  3. 奇偶分离:我们将数列中的奇数位置和偶数位置的数分别存储在两个数组 oddeven 中,并计算它们的前缀和。

  4. 遍历求最大和:对于奇数位置和偶数位置的前缀和数组,我们分别遍历,计算从第 k 个数开始的 k 个数的和,并与当前的最大和 ans 比较,如果更大,则更新 ans

  5. 输出结果:最后输出找到的最大和。

具体来说,如果数列中的所有数都是负数,那么最大和可能是这些负数中最大的一个(即最不负面的数),这个值可能小于或等于 0。在这种情况下,如果我们的 ans 是 0,我们就无法正确地识别出最大和,因为 0 已经被设置为初始的最大值。

因此,为了确保我们能够找到真正的最大和,无论数列中的数是正是负,将 ans 初始化为 INT_MIN 是一个更安全的选择。这样,任何实际的和都会大于 INT_MIN,确保我们能够正确地更新 ans 并最终找到最大和。

  • 判断当前元素的位置 i 是否为奇数(使用 i % 2 == 1 判断)
  • 如果是奇数:
  • 将 oddn(奇数位置的个数)加 1
  • 将当前元素 num 加到 odd[oddn - 1](前一个奇数位置的前缀和)上,得到新的前缀和,存储到 odd[oddn] 中

  • 循环从 k 开始,到 oddn 结束,oddn 是奇数位置的个数。
  • 对于每个奇数位置 i,计算从位置 i 开始的 k 个奇数位置的数的和,这可以通过 odd[i] - odd[i - k] 得到。这里 odd[i] 是到位置 i 的所有奇数位置的前缀和,odd[i - k] 是到位置 i - k 的所有奇数位置的前缀和,它们的差就是从位置 i - k + 1 到位置 i 的 k 个奇数位置的数的和。
  • 如果这个和大于当前的最大和 ans,则更新 ans

最大的勾

  • 考察动态规划、枚举

小蓝有一个长度为 n 的整数序列 a[1], a[2], …, a[n] 。

他希望从中找出一个最长的子序列,形成一个勾的形状(√)。

即找到 1 <= p[1] < p[2] < … < p[k] <= n,满足 a[p[1]] > a[p[2]] > a[p[3]] > … > a[p[x]] < a[p[x+1]] < … < a[p[k]] 。其中 k 是子序列的长度,x 是勾中最小的位置。目标是使得 k 最大。

请找出最大的勾的长度。

【输入格式】
输入的第一行包含一个整数 n 。

第二行包含 n 个整数,相邻数之间使用一个空格分隔,依次表示 a[1], a[2], …, a[n] 。

【输出格式】
输出一行,包含一个整数,表示答案。

【样例输入】
 

10
2 1 4 7 4 8 3 6 4 7


【样例输出】
 

5


【样例说明】
当 p = (4,5,7,9,10) 时,a[4] , a[5] , a[7] , a[9] , a[10] 可形成一个长度为 5 的勾:7,4,3,6,7

【评测用例规模与约定】
对于 30% 的评测用例,1 <= n <= 20 , 1 <= a[i] <= 100 。

对于 60% 的评测用例,1 <= n <= 100 , 1 <= a[i] <= 1000 。

对于所有评测用例,1 <= n <= 1000 , 1 <= a[i] <= 10000 。

思路 

  • 要求一个数最小,之后就是上升的样子,就成了“勾”
  • 首先将问题分解,将“勾”的左边与右边进行分解
  • 可以得到两个最长上升子序列问题
  • 然后将两个上升子学术论文合并起来即可 
  • 所以我们枚举“勾”的底部,得到前缀的最长下降子序列,后缀的最长上升子序列即可

代码

#include <stdio.h>

#define N 1010

int a[N];
int dppre[N], dpsuf[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }

    for (int i = 1; i <= n; ++i) {
        dppre[i] = 0; // 初始化
        for (int j = 1; j < i; ++j) {
            if (a[i] < a[j]) {
                if (dppre[j] + 1 > dppre[i]) {
                    dppre[i] = dppre[j] + 1;
                }
            }
        }
    }

    for (int i = n; i > 0; --i) {
        dpsuf[i] = 0; // 初始化
        for (int j = i + 1; j <= n; ++j) {
            if (a[i] < a[j]) {
                if (dpsuf[j] + 1 > dpsuf[i]) {
                    dpsuf[i] = dpsuf[j] + 1;
                }
            }
        }
    }

    int ans = 0;
    for (int i = 2; i < n; ++i) {
        if (dppre[i] > 0 && dpsuf[i] > 0 && dppre[i] + dpsuf[i] + 1 > ans) {
            ans = dppre[i] + dpsuf[i] + 1;
        }
    }
    printf("%d\n", ans);
    return 0;
}


http://www.kler.cn/a/458826.html

相关文章:

  • ListenAI 1.0.6 | 解锁订阅的文本转语音工具,支持朗读文档和网页
  • 强化学习方法分类详解
  • 前端Python应用指南(六)构建RESTful API:使用Flask和Django实现用户认证与授权
  • Presto-简单了解-230403
  • 计算机网络——期末复习(4)协议或技术汇总、思维导图
  • 《SwiftUI 实现点击按钮播放 MP3 音频》
  • HarmonyOS NEXT 实战之元服务:静态案例效果---本地生活服务
  • SkyWalking Agent 配置 Spring Cloud Gateway 插件解决日志错误
  • Momentum Contrast for Unsupervised Visual Representation Learning论文笔记
  • Django多字段认证的实现
  • python脚本加载ui页面:PySide6设计的页面
  • SQL 实战:窗口函数进阶 – 实现复杂滑动窗口与动态累计计算
  • 大数据与机器学习(它们有何关系?)
  • Mac电脑python多版本环境安装与切换
  • Selenium之Web元素定位
  • Android笔试面试题AI答之Android基础(7)
  • hive-sql 连续登录五天的用户
  • 【GeekBand】C++设计模式笔记18_State_状态模式
  • 【2024年-6月-21日-开源社区openEuler实践记录】探索 intel-kernel:英特尔架构内核优化之路
  • [TOTP]android kotlin实现 totp身份验证器 类似Google身份验证器
  • 环,域,体,整区,理想,极大理想,
  • 配置hive支持中文注释
  • Lombok是银弹?还是陷阱?
  • golang标准库archive/tar实现打包压缩及解压
  • 《Java核心技术 卷II》流的创建
  • Vue el-data-picker选中开始时间,结束时间自动加半小时