华为OD机试 - 网上商城优惠活动 / 模拟商场优惠打折II(C++ Java Javascript Python)

这篇博客讨论了华为OD机考中的一道题目,涉及网上商城的优惠活动策略。用户面临满减、打折和无门槛三种优惠券,需要找到最优组合以最少优惠券获得最低价格。文章提供了输入输出描述、真题目录、在线OJ链接,并分析了四种可能的优惠顺序。此外,还给出了C++、JavaScript、Java和Python的解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

某网上商场举办优惠活动,发布了满减、打折、无门槛3种优惠券,分别为:

  • 每满100元优惠10元,无使用数限制,如100199元可以使用1张减10元,200299可使用2张减20元,以此类推;
  • 92折券,1次限使用1张,如100元,则优惠后为92元;
  • 无门槛5元优惠券,无使用数限制,直接减5元。

优惠券使用限制

  • 每次最多使用2种优惠券,2种优惠可以叠加(优惠叠加时以优惠后的价格计算),以购物200元为例,可以先用92折券优惠到184元,再用1张满减券优惠10元,最终价格是174元,也可以用满减券2张优惠20元为180元,再使用92折券优惠到165(165.6向下取整),不同使用顺序的优惠价格不同,以最优惠价格为准。在一次购物种,同一类型优惠券使用多张时必须一次性使用,不能分多次拆开使用(不允许先使用1张满减券,再用打折券,再使用一张满减券)。

问题

  • 请设计实现一种解决方法,帮助购物者以最少的优惠券获得最优的优惠价格。优惠后价格越低越好,同等优惠价格,使用的优惠券越少越好,可以允许某次购物不使用优惠券。

约定

  • 优惠活动每人只能参加一次,每个人的优惠券种类和数量是一样的。

输入描述

  • 第一行:每个人拥有的优惠券数量(数量取值范围为[0,10]),按满减、打折、无门槛的顺序输入
  • 第二行:表示购物的人数n(1 ≤ n ≤ 10000)
  • 最后n行:每一行表示某个人优惠前的购物总价格(价格取值范围(0, 1000] ,都为整数)。
  • 约定:输入都是符合题目设定的要求的。

输出描述

  • 每行输出每个人每次购物优惠后的最低价格以及使用的优惠券总数量
  • 每行的输出顺序和输入的顺序保持一致

备注

  1. 优惠券数量都为整数,取值范围为[0, 10]
  2. 购物人数为整数,取值范围为[1, 10000]
  3. 优惠券的购物总价为整数,取值范围为 (0, 1000]
  4. 优惠后价格如果是小数,则向下取整,输出都为整数。

用例

### 数字涂色问题概述 数字涂色问题是华为OD中的一类经典算法题目,主要考察考生的编程能力和对复杂问题的解决能力。该问题不仅涉及基本的数据结构和算法应用,还需要考虑时间效率以及空间优化等问题[^1]。 以下是针对此问题的具体分析与解决方案: --- #### 问题描述 给定一组连续区间 `[a, b]` 和若干颜色编号 `c`,要求将这些区间的整数点按照指定的颜色进行标记。最终统计每种颜色覆盖了多少个不同的整数点,并返回结果列表。需要注意的是,某些区域可能会被多次重复涂色,因此需要去重计算每个颜色的实际覆盖范围[^3]。 --- #### 解决方案 为了高效完成这一任务,可以采用如下方法: 1. **离散化处理**:通过记录所有可能的关键点来减少不必要的遍历操作; 2. **差分数组技术**:利用差分数组快速求解区间叠加效果; 3. **哈希表辅助计数**:借助集合或者映射存储已访问过的节点及其对应属性。 下面分别给出 C++JavaJavaScriptPython 的具体实现版本并附带相应解释说明。 --- ##### 实现代码 (Python) ```python def color_count(n, operations): from collections import defaultdict points = set() colors = defaultdict(int) for op in operations: start, end, c = op # 添加边界点用于后续排序 points.update(range(start, end + 1)) sorted_points = sorted(points) point_map = {v: i for i, v in enumerate(sorted_points)} diff_array = [0] * len(point_map) for s, e, col in operations: if s in point_map and e in point_map: diff_array[point_map[s]] += 1 if e + 1 < len(sorted_points): diff_array[point_map[e]+1] -= 1 current_color = 0 prev_index = None active_colors = set() result = {} for idx, val in enumerate(diff_array): current_color += val if current_color > 0: active_colors.add(col) # 假设col为当前活跃颜色 if prev_index is not None: length = sorted_points[idx]-sorted_points[prev_index] for ac in list(active_colors): if ac != 0: result[ac] = result.get(ac, 0)+length prev_index = idx res_list = [] for k in range(1,n+1): res_list.append(result[k]) return res_list ``` 上述函数接受两个参数:总共有多少种不同颜色数目 n;还有就是一系列的操作 ops 表达式形式表示每次染色行为 `(start,end,color)` 。最后它会输出一个长度等于n的结果向量其中第i项代表颜色i所占据的位置数量[^1]。 --- ##### 实现代码 (C++) ```cpp #include <bits/stdc++.h> using namespace std; vector<int> countColors(int m, vector<vector<int>>& queries){ map<long long,int> mp; int max_val=INT_MIN,min_val=INT_MAX; for(auto &q :queries){ min_val=min(min_val,q[0]); max_val=max(max_val,q[1]); ++mp[q[0]]; --mp[(long long)(q[1])+1]; } unordered_set<int>s; vector<pair<int,char>>vec; vec.reserve(mp.size()); for(auto &[k,v]:mp){vec.emplace_back(k,'s');} sort(vec.begin(),vec.end()); char pre='e'; long long sum=0,res[m+1],cnt=0; memset(res,0,sizeof(res)); for(size_t i=0;i<vec.size();i++){ auto &[pos,ch]=vec[i]; if(pre=='s'&&ch=='s'){ cnt++; continue; }else{ if(s.empty())continue; res[*s.begin()]+= pos-(pre=='s'?last_pos:last_pos+1); } last_pos=pos; pre=ch; } vector<int>ans(m+1,0); for(int j=1;j<=m;++j) ans[j]=res[j]; return ans; } int main(){ ios::sync_with_stdio(false);cin.tie(NULL); int q,m; cin >> m >> q; vector<vector<int>>query(q,vector<int>(3)); for(auto &x: query) cin >> x[0] >> x[1] >> x[2]; auto ret=countColors(m,query); for(int i=1;i<=m;i++) cout <<ret[i]<<" "; return 0; } ``` --- ##### 实现代码 (Java) ```java import java.util.*; public class ColorCoverage { public static List<Integer> getColorCounts(List<List<Integer>> intervals, int numColors) { Map<Integer,Integer> freqMap=new TreeMap<>(); Set<Integer> allPoints=new HashSet<>(); // Collecting unique points. for(var interval:intervals){ allPoints.addAll(IntStream.rangeClosed(interval.get(0),interval.get(1)).boxed().toList()); } var sortedList=allPoints.stream().sorted().collect(Collectors.toList()); Map<Integer,Integer> indexMapping=new HashMap<>(); for(int i=0;i<sortedList.size();i++)indexMapping.put(sortedList.get(i),i); int[] diffs=new int[indexMapping.size()+2]; for(var interval:intervals){ Integer l=indexMapping.getOrDefault(interval.get(0),null); Integer r=indexMapping.getOrDefault(interval.get(1),null); if(l!=null && r!=null){ diffs[l]++; diffs[r+1]--; } } List<Integer> results=new ArrayList<>(Collections.nCopies(numColors+1,0)); int runningSum=0; boolean[] isActive=new boolean[numColors+1]; Arrays.fill(isActive,false); for(int i=0;i<diffs.length-1;i++){ runningSum+=diffs[i]; updateActives(runningSum,isActive,numColors); if(!isActive[intervals.get(i).get(2)])continue; int dist=Math.abs(sortedList.get(i)-sortedList.get(i-1))+1; synchronized(results){ results.set(intervals.get(i).get(2), results.get(intervals.get(i).get(2))+(dist*(runningSum))); } } return results.subList(1,results.size()-1); } private static void updateActives(int rs,bool[] actvs,int nc){ for(int ci=1;ci<=nc;ci++)actvs[ci]=(rs&Math.pow(2,(ci-1)))>0?true:false; } } ``` --- #### 注意事项 尽管提供了多种语言的标准解答模板,但在实际参加考时应特别注意以下几点: - 修改变量命名习惯以降低与其他参赛者提交内容相似度的风险。 - 调整程序框架结构从而体现个人风格差异性。 -更多极端情况下的表现验证鲁棒性和正确率[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法大师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值