#P4524. 第2题-奶茶店的超级收益日
-
1000ms
Tried: 86
Accepted: 32
Difficulty: 3
所属公司 :
华为
时间 :2025年12月4日-留学生非AI方向(通软&嵌软&测试&算法&数据科学)
-
算法标签>模拟
第2题-奶茶店的超级收益日
解题思路
题意:
给出连续 (n) 天的收入数组 a[0..n-1]。
如果某一天 i 的收入 a[i] 大于它后面某一天收入的两倍(存在 j > i,使得 a[i] > 2 * a[j]),则这一天为“超级收益日”。
问在这段时间里共有多少个超级收益日。
关键观察:
- 对于某一天
i,要找是否存在某个j>i满足a[i] > 2*a[j]。 - 若把
i之后所有天的最小收入记作min_suffix[i+1],则 是否为超级收益日 等价于:a[i] > 2 * min_suffix[i+1]。 因为如果对最小的收入都不大于两倍,对其他更大的收入就更不可能大于两倍。
算法(从右往左单次扫描 + 维护后缀最小值):
-
特殊情况:若
n<=1,没有后面一天,答案为 0。 -
从最后一天开始,维护变量
suffixMin表示“当前天之后所有天的最小收入”。- 初始化:
suffixMin = a[n-1],最后一天一定不是超级收益日。
- 初始化:
-
从倒数第二天开始往前遍历
i = n-2 ... 0:- 若
a[i] > 2 * suffixMin,说明存在后面某天收入不超过suffixMin,当前天一定是超级收益日,计数cnt++。 - 然后更新
suffixMin = min(suffixMin, a[i]),为前面更早的天做准备。
- 若
-
输出计数
cnt。
使用的算法思想: 线性扫描 + 后缀最小值(类似单调思路),一次遍历即可完成判断。
复杂度分析
- 时间复杂度: 只需从右向左遍历数组一次,时间复杂度为 O(n)。
- 空间复杂度: 只使用若干辅助变量(计数器、后缀最小值),额外空间为 O(1)。
代码实现
Python
# 功能函数:统计超级收益日的天数
def count_super_days(arr):
n = len(arr)
# 不足两天,不可能有超级收益日
if n <= 1:
return 0
# 后缀最小值,初始为最后一天的收入
suffix_min = arr[-1]
count = 0
# 从倒数第二天开始往前遍历
for i in range(n - 2, -1, -1):
# 判断当前天是否大于后面某天收入的两倍
if arr[i] > 2 * suffix_min:
count += 1
# 更新后缀最小值
if arr[i] < suffix_min:
suffix_min = arr[i]
return count
if __name__ == "__main__":
import sys
data = list(map(int, sys.stdin.read().split()))
if not data:
# 无输入直接结束
sys.exit(0)
n = data[0] # 天数
incomes = data[1:1 + n] # 每天的收入数组
# 调用功能函数并输出结果
ans = count_super_days(incomes)
print(ans)
Java
import java.util.Scanner;
public class Main {
// 功能函数:统计超级收益日的天数
public static int countSuperDays(int[] a) {
int n = a.length;
if (n <= 1) {
// 不足两天,直接返回 0
return 0;
}
int suffixMin = a[n - 1]; // 后缀最小值,初始为最后一天
int count = 0;
// 从倒数第二天开始往前遍历
for (int i = n - 2; i >= 0; i--) {
// 判断当前天是否大于后面某天收入的两倍
if (a[i] > 2 * suffixMin) {
count++;
}
// 更新后缀最小值
if (a[i] < suffixMin) {
suffixMin = a[i];
}
}
return count;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 读取天数
if (!sc.hasNextInt()) {
sc.close();
return;
}
int n = sc.nextInt();
// 读取每天的收入
int[] incomes = new int[n];
for (int i = 0; i < n; i++) {
incomes[i] = sc.nextInt();
}
sc.close();
// 调用功能函数并输出结果
int ans = countSuperDays(incomes);
System.out.println(ans);
}
}
C++
#include <bits/stdc++.h>
using namespace std;
// 功能函数:统计超级收益日的天数
int countSuperDays(const vector<int> &a) {
int n = (int)a.size();
if (n <= 1) {
// 不足两天,没有超级收益日
return 0;
}
int suffixMin = a[n - 1]; // 后缀最小值,初始为最后一天
int count = 0;
// 从倒数第二天开始往前遍历
for (int i = n - 2; i >= 0; --i) {
// 判断当前天是否为超级收益日
if (a[i] > 2 * suffixMin) {
count++;
}
// 更新后缀最小值
if (a[i] < suffixMin) {
suffixMin = a[i];
}
}
return count;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
// 读取天数
if (!(cin >> n)) {
return 0;
}
// 读取每天的收入
vector<int> incomes(n);
for (int i = 0; i < n; ++i) {
cin >> incomes[i];
}
// 调用功能函数并输出结果
int ans = countSuperDays(incomes);
cout << ans << "\n";
return 0;
}
题目内容
商场新开了一家奶茶店,店长 A 每天统计当天的收入,连续统计 n 天,用以查看收入的趋势。如果某一天的收入比后面第一天的两倍收入还多,则认为这一天是超级收益日。要求计算这段时间内这样的超圾收益日有多少天。
输入描述
第一行输入一个数字,表示统计的天数,天数的范围为 [0,1000]
第二行输入一串数字,为一段时间内每天的收入情况,可表示为整数数组,数组规模与天数对应,收入的取值范围为 [0,100000]
输出描述
超级收益日的天数,为整数
样例1
输入
5
2 4 3 5 1
输出
3
说明
共 5 天的收入情况,其中第 2 天收入 4 ,大于第 5 天收入 1∗2 ;第 3 天收入 3 ,大于第 5 天收入 1∗2 ;
第 4 天收入 5 ,大于第 5 天收入 1∗2 。所以有 3 天为超级收入日。
样例2
输入
5
1 3 2 3 1
输出
2
说明
共 5 天的收入情况,其中第 2 天收入 3 ,大于第 5 天收入 1∗2 ; 第 4 天收入 3 ,大于第 5 天收入 12 。所以有 2 天为超级收入日。