题解:学而思编程 签到积分

【题目来源】

学而思编程:签到积分

【题目描述】

小猴手机中的某一个应用程序每天可以签到获取积分,当天签到至少可以获得 \(1\) 积分,如果前一天也签到了,则当天获得积分是前一天获得积分数量加 \(1\),但是一天最多只能获得 \(7\) 积分。

现在给出一个由 \(1\)\(0\) 组成的整数序列,该序列表示小猴连续 \(n\) 天的签到情况,其中 \(1\) 表示当天签到,\(0\) 表示当天未签到。请你帮助小猴计算这 \(n\) 天一共获得了多少积分。

【输入】

第一行一个正整数 \(n\),表示小猴签到的天数;

第二行 \(n\) 个整数,表示小猴连续 \(n\) 天的签到情况。

【输出】

一行一个整数,表示小猴获得的积分总数。

【输入样例】

3
1 0 1

【输出样例】

2

【核心思想】

  1. 问题分析:给定 \(n\) 天的签到序列(\(1\) 表示签到,\(0\) 表示未签到),计算总积分。积分规则:连续第 \(k\) 天签到获得 \(k\) 积分(上限 \(7\)),中断后重新从 \(1\) 开始。这是一个线性扫描 + 状态维护问题,关键在于维护当前连续签到天数,并根据上限规则累加积分。

  2. 算法选择

    • 连续计数器k 记录当前连续签到天数,每天签到时递增(上限 \(7\)),未签到时重置为 \(0\)
    • 贪心累加:每天签到获得的积分即为当前连续天数(不超过 \(7\)),直接累加
  3. 关键步骤

    • 初始化:读取 \(n\) 和签到数组 \(a[1..n]\)
    • ans = 0k = 0
    • 线性扫描(遍历 \(i\)\(1\)\(n\)):
      • a[i] == 1(当天签到):
        • k < 7k++(连续天数递增,上限 \(7\)
        • ans += k:累加当天积分(第 \(k\) 天连续签到得 \(k\) 分)
      • 否则(未签到):
        • k = 0:重置连续计数器
    • 输出 ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),线性扫描
    • 空间复杂度:\(O(n)\),存储签到数组(可优化至 \(O(1)\) 在线处理)
  5. 连续计数器的核心思想

    • 状态转移k 作为状态变量,只在签到时递增、未签到时重置,完美模拟连续签到的积分增长
    • 上限截断k < 7 时递增,否则保持 \(7\),实现"最多 \(7\) 积分"的约束
    • 积分公式化:第 \(i\) 天签到的积分 = \(\min(\text{当前连续天数}, 7)\),由于 k 已维护为截断后的值,直接累加即可
    • 中断即重置:未签到时 k = 0,确保下次签到从 \(1\) 开始,符合"前一天也签到"的递推条件
    • 适用于"连续状态奖励 + 上限约束"类问题,单变量维护即可实现递推计算

【算法标签】

数学

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int n;  // 数组长度
int a[100005];  // 存储输入数组
int ans;  // 最终得分
int k;  // 当前连续1的计数器

int main()
{
    cin >> n;  // 输入数组长度

    // 输入数组元素
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }

    // 遍历数组计算得分
    for (int i = 1; i <= n; i++)
    {
        if (a[i] == 1)  // 如果当前元素是1
        {
            if (k < 7)  // 如果连续1的计数器小于7
            {
                k++;  // 计数器加1
            }
            ans += k;  // 累加当前得分
        }
        else  // 如果当前元素不是1
        {
            k = 0;  // 重置连续1的计数器
        }
    }

    cout << ans << endl;  // 输出总得分

    return 0;  // 程序正常结束
}

【运行结果】

3
1 0 1
2
posted @ 2026-07-05 14:50  团爸讲算法  阅读(5)  评论(0)    收藏  举报