题目思路解析

这道题目模拟了12个月的零花钱管理过程,考察状态模拟边界条件处理能力。我们需要跟踪津津每个月的资金流动情况,判断是否会出现资金不足的情况,并计算年终总金额。

核心思考路径

  1. 初始化状态:津津初始手头金额为0,储蓄金额为0
  2. 月度循环处理
    • 每月月初获得300元
    • 检查是否足够支付当月预算
    • 执行储蓄计划(整百存储)
  3. 年终结算:计算储蓄利息和总金额

关键考核知识点

1. 状态跟踪与更新(⭐⭐⭐⭐⭐)

  • 资金流动记录:需要维护两个变量
    • current_money:手中现金
    • saved_money:储蓄金额
  • 月度状态转移
    current_money += 300;  // 月初收入
    if (current_money < budget) {  // 资金不足
        return -current_month;
    }
    current_money -= budget;  // 支付预算
    

2. 储蓄逻辑实现(⭐⭐⭐⭐)

  • 整百存储规则
    if (current_money >= 100) {
        int save = (current_money / 100) * 100;
        saved_money += save;
        current_money -= save;
    }
    

3. 边界条件处理(⭐⭐⭐)

  • 资金不足判断:检查current_money + 300 < budget
  • 年终计算精度:利息计算1.2 * saved_money
  • 月份索引处理:输出负月份时注意起始值

C++完整实现

#include <iostream>
#include <vector>
#include <iomanip>

using namespace std;

int calculateSavings(const vector<int>& budgets) {
    int current_money = 0;
    int saved_money = 0;
    
    for (int month = 0; month < 12; ++month) {
        // 月初获得300元
        current_money += 300;
        
        // 检查是否足够支付预算
        if (current_money < budgets[month]) {
            return -(month + 1);  // 返回负月份(1-based)
        }
        
        // 支付预算
        current_money -= budgets[month];
        
        // 储蓄整百金额
        if (current_money >= 100) {
            int save = (current_money / 100) * 100;
            saved_money += save;
            current_money -= save;
        }
    }
    
    // 年终计算(利息20%)
    return current_money + saved_money * 1.2;
}

int main() {
    vector<int> budgets(12);
    for (int i = 0; i < 12; ++i) {
        cin >> budgets[i];
    }
    
    int result = calculateSavings(budgets);
    
    if (result < 0) {
        cout << result << endl;
    } else {
        cout << result << endl;
    }
    
    return 0;
}

代码解析与优化

1. 输入处理优化

// 使用vector预分配空间避免动态扩容
vector<int> budgets(12);
for (auto& budget : budgets) {
    cin >> budget;
}

2. 利息计算优化

// 避免浮点数运算,使用整数计算
int total = current_money + saved_money + saved_money / 5;

3. 提前终止机制

// 发现资金不足立即返回
if (current_money < budgets[month]) {
    return -(month + 1);
}

测试用例分析

测试案例 输入预算 预期输出 验证要点
案例1 [290,230,...,60] -7 资金不足情况
案例2 [90,230,...,60] 1890 完整年度计算
边界1 [300]*12 360 每月刚好花完
边界2 [0]*12 4320 全部储蓄情况
特殊1 [350,0,...,0] -1 首月不足

常见错误与修正

错误1:月份索引处理

// 错误:返回0-based索引
return -month;  // 应该是month+1

修正

return -(month + 1);

错误2:利息计算精度

// 错误:直接使用浮点乘法
double total = current_money + saved_money * 1.2;

修正

int total = current_money + saved_money + saved_money / 5;

错误3:储蓄条件遗漏

// 错误:忽略恰好100元的情况
if (current_money > 100)  // 应该是>=

修正

if (current_money >= 100)

竞赛技巧总结

  1. 状态简化:只需跟踪两个变量,无需记录每月详情
  2. 提前终止:发现资金不足立即退出循环
  3. 整数运算:避免浮点数带来的精度问题
  4. 边界测试:特别注意首月和末月的情况

拓展思考

  1. 变形问题1:如果妈妈给的钱每月不同怎么办?

    vector<int> incomes(12);
    // 修改状态更新逻辑
    current_money += incomes[month];
    
  2. 变形问题2:允许中途取出储蓄(带惩罚)

    // 增加储蓄取出逻辑
    if (need_withdraw) {
        current_money += saved_money * 0.8;  // 20%惩罚
        saved_money = 0;
    }
    
  3. 进阶挑战:多年度连续计算

    // 增加年份循环
    for (int year = 0; year < years; ++year) {
        // 年度计算逻辑
    }
    

"编程竞赛中的模拟题,关键在于准确理解状态转移规则。通过这道题,我们掌握了资金流动模拟的核心技巧。"

关注并私信【储蓄】可获得:

  • NOIP真题解析
  • C++标准库文档

 

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐