题解:洛谷 P5719 分类平均
【题目来源】
【题目描述】
给定 \(n\) 和 \(k\),将从 $1 $ 到 \(n\) 之间的所有正整数可以分为两类:$A $ 类数可以被 \(k\) 整除(也就是说是 \(k\) 的倍数),而 $B $ 类数不能。请输出这两类数的平均数,精确到小数点后 $1 $ 位,用空格隔开。
数据保证两类数的个数都不会是 \(0\)。
【输入】
输入两个正整数 \(n\) 与 \(k\)。
【输出】
输出一行,两个实数,分别表示 \(A\) 类数与 \(B\) 类数的平均数。精确到小数点后一位。
【输入样例】
100 16
【输出样例】
56.0 50.1
【核心思想】
-
问题分析:给定 \(n\) 和 \(k\),将 \(1 \sim n\) 的正整数分为两类:\(A\) 类(\(k\) 的倍数)和 \(B\) 类(非 \(k\) 的倍数)。分别计算两类数的平均数,精确到小数点后 \(1\) 位。
-
算法选择:
- 单次遍历分类统计:遍历 \(1 \sim n\),用模运算判断类别,分别累加和与计数
- 浮点除法:用
1.0 * sum / cnt将整数除法转为浮点除法,确保结果精确
-
关键步骤:
- 读入数据:
cin >> n >> k - 初始化统计变量:
sum1 = sum2 = 0,c1 = c2 = 0 - 遍历分类(\(i\) 从 \(1\) 到 \(n\)):
- 若
i % k == 0:sum1 += i,c1++(\(A\) 类) - 否则:
sum2 += i,c2++(\(B\) 类)
- 若
- 计算平均数:
avg1 = 1.0 * sum1 / c1avg2 = 1.0 * sum2 / c2
- 格式化输出:
printf("%.1f %.1f", avg1, avg2)
- 读入数据:
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),遍历 \(1 \sim n\) 一次
- 空间复杂度:\(O(1)\),仅需常数个变量
-
分类统计的核心思想:
- 模运算分类:
i % k == 0是判断 \(k\) 的倍数的充要条件,\(O(1)\) 时间完成分类 - 同步累加:遍历过程中同时维护两个类别的和与个数,避免二次遍历
- 浮点转换技巧:
1.0 * sum将整数转为浮点数,确保除法结果为浮点型 - 数据保证:题目保证两类数个数均不为 0,无需处理除零情况
- 适用于分类统计、均值计算、模运算应用类入门问题
- 模运算分类:
【算法标签】
入门 #模拟
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
/**
* 主函数 - 程序入口
* @return 程序执行状态码(0表示成功)
*/
int main()
{
int n, k; // 定义变量:n(数字范围上限), k(倍数判断条件)
int sum1 = 0, sum2 = 0; // 定义变量:sum1(k的倍数的和), sum2(非k倍数的和)
int c1 = 0, c2 = 0; // 定义变量:c1(k的倍数的个数), c2(非k倍数的个数)
double avg1, avg2; // 定义变量:avg1(k倍数的平均值), avg2(非k倍数的平均值)
cin >> n >> k; // 输入数字范围n和倍数k
// 遍历1到n的所有数字
for (int i = 1; i <= n; i++)
{
if (i % k == 0) // 判断是否为k的倍数
{
sum1 += i; // 累加到k倍数的和
c1++; // 计数k倍数的个数
}
else
{
sum2 += i; // 累加到非k倍数的和
c2++; // 计数非k倍数的个数
}
}
// 计算平均值(注意转换为浮点数计算)
avg1 = 1.0 * sum1 / c1; // k倍数的平均值
avg2 = 1.0 * sum2 / c2; // 非k倍数的平均值
// 输出结果(保留1位小数)
printf("%.1f %.1f", avg1, avg2);
return 0; // 程序正常结束
}
【运行结果】
100 16
56.0 50.1
浙公网安备 33010602011771号