当前位置: 首页 > news >正文

【华为OD】数字游戏

【华为OD】数字游戏

题目描述

小明玩一个游戏。系统发 1+n 张牌,每张牌上有一个整数。第一张给小明,后 n 张按照发牌顺序排成连续的一行。

需要小明判断,后 n 张牌中,是否存在连续的若干张牌,其和可以整除小明手中牌上的数字。

输入描述

输入数据有多组,每组输入数据有两行,输入到文件结尾结束。

  • 第一行有两个整数 n 和 m,空格隔开。m 代表发给小明牌上的数字。
  • 第二行有 n 个数,代表后续发的 n 张牌上的数字,以空格隔开。

输出描述

对每组输入,如果存在满足条件的连续若干张牌,则输出1;否则,输出0。

备注

  • 1 ≤ n ≤ 1000
  • 1 ≤ 牌上的整数 ≤ 400000
  • 输入的数组,不多于 1000
  • 用例确保输入都正确,不需要考虑非法情况。

示例

示例一

输入:

6 7
2 12 6 3 5 5

输出:

1

示例二

输入:

10 11
1 1 1 1 1 1 1 1 1 1

输出:

0

说明:
两组输入。

  • 第一组小明牌的数字为 7,再发了6张牌。第1、2两张牌数字和为 14,可以整除7,输出 1
  • 第二组小明牌的数字为 11,再发了10张牌,这10张牌数字和为10,无法整除 11,输出0。

解题思路

这是一个子数组和整除问题,需要判断是否存在连续子数组的和能被给定数字整除。

核心思想:

  1. 枚举所有可能的连续子数组
  2. 计算每个子数组的和
  3. 判断是否能被目标数字整除

我将提供两种解法:暴力枚举法前缀和优化法

解法一:暴力枚举法

枚举所有可能的连续子数组,计算每个子数组的和并判断是否能被目标数字整除。

Java实现

import java.util.*;public class Solution1 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNextLine()) {String line = sc.nextLine().trim();if (line.isEmpty()) break;String[] parts = line.split(" ");int n = Integer.parseInt(parts[0]);int m = Integer.parseInt(parts[1]);if (!sc.hasNextLine()) break;String[] numStrs = sc.nextLine().split(" ");int[] nums = new int[n];for (int i = 0; i < n; i++) {nums[i] = Integer.parseInt(numStrs[i]);}boolean found = false;// 枚举所有可能的连续子数组for (int i = 0; i < n && !found; i++) {int sum = 0;for (int j = i; j < n; j++) {sum += nums[j];if (sum % m == 0) {found = true;break;}}}System.out.println(found ? 1 : 0);}sc.close();}
}

Python实现

import sysdef solve_brute_force():lines = []for line in sys.stdin:lines.append(line.strip())i = 0while i < len(lines):if not lines[i]:breakparts = lines[i].split()n, m = int(parts[0]), int(parts[1])if i + 1 >= len(lines):breaknums = list(map(int, lines[i + 1].split()))found = False# 枚举所有可能的连续子数组for start in range(n):current_sum = 0for end in range(start, n):current_sum += nums[end]if current_sum % m == 0:found = Truebreakif found:breakprint(1 if found else 0)i += 2solve_brute_force()

C++实现

#include <iostream>
#include <vector>
#include <sstream>
using namespace std;int main() {string line;while (getline(cin, line)) {if (line.empty()) break;istringstream iss(line);int n, m;iss >> n >> m;if (!getline(cin, line)) break;istringstream numStream(line);vector<int> nums(n);for (int i = 0; i < n; i++) {numStream >> nums[i];}bool found = false;// 枚举所有可能的连续子数组for (int i = 0; i < n && !found; i++) {int sum = 0;for (int j = i; j < n; j++) {sum += nums[j];if (sum % m == 0) {found = true;break;}}}cout << (found ? 1 : 0) << endl;}return 0;
}

解法二:前缀和 + 同余定理优化法

使用前缀和和同余定理来优化算法。如果两个前缀和对m的余数相同,那么它们之间的子数组和必定能被m整除。

Java实现

import java.util.*;public class Solution2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNextLine()) {String line = sc.nextLine().trim();if (line.isEmpty()) break;String[] parts = line.split(" ");int n = Integer.parseInt(parts[0]);int m = Integer.parseInt(parts[1]);if (!sc.hasNextLine()) break;String[] numStrs = sc.nextLine().split(" ");int[] nums = new int[n];for (int i = 0; i < n; i++) {nums[i] = Integer.parseInt(numStrs[i]);}boolean found = false;Set<Integer> remainders = new HashSet<>();remainders.add(0); // 前缀和为0的余数int prefixSum = 0;for (int i = 0; i < n; i++) {prefixSum += nums[i];int remainder = prefixSum % m;// 如果当前余数已经出现过,说明存在子数组和能被m整除if (remainders.contains(remainder)) {found = true;break;}remainders.add(remainder);}System.out.println(found ? 1 : 0);}sc.close();}
}

Python实现

import sysdef solve_optimized():lines = []for line in sys.stdin:lines.append(line.strip())i = 0while i < len(lines):if not lines[i]:breakparts = lines[i].split()n, m = int(parts[0]), int(parts[1])if i + 1 >= len(lines):breaknums = list(map(int, lines[i + 1].split()))found = Falseremainders = {0}  # 前缀和为0的余数prefix_sum = 0for num in nums:prefix_sum += numremainder = prefix_sum % m# 如果当前余数已经出现过,说明存在子数组和能被m整除if remainder in remainders:found = Truebreakremainders.add(remainder)print(1 if found else 0)i += 2solve_optimized()

C++实现

#include <iostream>
#include <vector>
#include <unordered_set>
#include <sstream>
using namespace std;int main() {string line;while (getline(cin, line)) {if (line.empty()) break;istringstream iss(line);int n, m;iss >> n >> m;if (!getline(cin, line)) break;istringstream numStream(line);vector<int> nums(n);for (int i = 0; i < n; i++) {numStream >> nums[i];}bool found = false;unordered_set<int> remainders;remainders.insert(0); // 前缀和为0的余数int prefixSum = 0;for (int i = 0; i < n; i++) {prefixSum += nums[i];int remainder = prefixSum % m;// 如果当前余数已经出现过,说明存在子数组和能被m整除if (remainders.find(remainder) != remainders.end()) {found = true;break;}remainders.insert(remainder);}cout << (found ? 1 : 0) << endl;}return 0;
}

解法三:简化版前缀和优化(推荐)

考虑到输入处理的复杂性,提供一个更简洁的版本:

Java实现

import java.util.*;public class Solution3 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNext()) {int n = sc.nextInt();int m = sc.nextInt();int[] nums = new int[n];for (int i = 0; i < n; i++) {nums[i] = sc.nextInt();}boolean found = false;Set<Integer> remainders = new HashSet<>();remainders.add(0);int prefixSum = 0;for (int num : nums) {prefixSum += num;int remainder = prefixSum % m;if (remainders.contains(remainder)) {found = true;break;}remainders.add(remainder);}System.out.println(found ? 1 : 0);}sc.close();}
}

Python实现

def solve_simple():try:while True:line = input().split()n, m = int(line[0]), int(line[1])nums = list(map(int, input().split()))found = Falseremainders = {0}prefix_sum = 0for num in nums:prefix_sum += numremainder = prefix_sum % mif remainder in remainders:found = Truebreakremainders.add(remainder)print(1 if found else 0)except EOFError:passsolve_simple()

C++实现

#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;int main() {int n, m;while (cin >> n >> m) {vector<int> nums(n);for (int i = 0; i < n; i++) {cin >> nums[i];}bool found = false;unordered_set<int> remainders;remainders.insert(0);int prefixSum = 0;for (int num : nums) {prefixSum += num;int remainder = prefixSum % m;if (remainders.find(remainder) != remainders.end()) {found = true;break;}remainders.insert(remainder);}cout << (found ? 1 : 0) << endl;}return 0;
}

算法复杂度分析

解法一:暴力枚举法

  • 时间复杂度:O(N²),需要枚举所有可能的子数组
  • 空间复杂度:O(1)

解法二:前缀和 + 同余定理优化法

  • 时间复杂度:O(N),只需要一次遍历
  • 空间复杂度:O(min(N, M)),存储余数的集合

算法原理详解

同余定理的应用

关键洞察:如果存在两个前缀和 prefixSum[i]prefixSum[j] (i < j),使得:

prefixSum[i] ≡ prefixSum[j] (mod m)

那么子数组 nums[i+1...j] 的和就能被 m 整除,因为:

sum(nums[i+1...j]) = prefixSum[j] - prefixSum[i] ≡ 0 (mod m)

特别地,如果某个前缀和本身就能被 m 整除(余数为0),那么从开头到该位置的子数组和就能被 m 整除。

示例分析

示例一分析

数组:[2, 12, 6, 3, 5, 5],m = 7

前缀和计算过程:

  • 位置0:prefixSum = 2,余数 = 2 % 7 = 2
  • 位置1:prefixSum = 2 + 12 = 14,余数 = 14 % 7 = 0

由于余数为0,说明前两个元素的和(14)能被7整除,输出1。

示例二分析

数组:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],m = 11

所有前缀和的余数都是1到10之间的数,没有重复的余数,且没有余数为0的情况,所以不存在能被11整除的子数组和,输出0。

总结

两种解法各有特点:

  1. 暴力枚举法:思路直观,容易理解,但时间复杂度较高
  2. 前缀和 + 同余定理优化法:利用数学性质优化算法,时间复杂度降为O(N),是最优解法

对于这道题目,由于 n ≤ 1000,两种方法都能通过,但前缀和 + 同余定理优化法更加高效,特别适合处理大规模数据。

关键技巧是理解同余定理在子数组和问题中的应用:如果两个前缀和的余数相同,那么它们之间的子数组和必定能被目标数整除。这个性质大大简化了问题的求解过程。


文章转载自:

http://9g9uCIA8.gryzk.cn
http://1odqdivL.gryzk.cn
http://SoalSuzq.gryzk.cn
http://sSzBT1Oa.gryzk.cn
http://EbdxAWxG.gryzk.cn
http://p1RmnTJb.gryzk.cn
http://zSzVdQGW.gryzk.cn
http://ZDnTrazv.gryzk.cn
http://PyveDC4Y.gryzk.cn
http://V8EP3NtY.gryzk.cn
http://53Ry1JzX.gryzk.cn
http://NjohOiYC.gryzk.cn
http://E58NV95L.gryzk.cn
http://aaNUbT7X.gryzk.cn
http://s3rX6aSN.gryzk.cn
http://ReihPKNu.gryzk.cn
http://QY6vOsk9.gryzk.cn
http://1lNnR2ah.gryzk.cn
http://YGQDwm3j.gryzk.cn
http://q6PoMaAY.gryzk.cn
http://CbjyJ0AP.gryzk.cn
http://G0ow7SB8.gryzk.cn
http://SeNDpAZz.gryzk.cn
http://WnLdke8t.gryzk.cn
http://YEZ768vF.gryzk.cn
http://6TB3ZwEy.gryzk.cn
http://RzJn370X.gryzk.cn
http://T7Tblyrl.gryzk.cn
http://thqgUo29.gryzk.cn
http://FtvTznrc.gryzk.cn
http://www.dtcms.com/a/374449.html

相关文章:

  • 分享:一种为蓝牙、WIFI、U段音频发射设备提供ARC回传数字音频桥接功能的方案
  • 【设计模式】 外观模式
  • 在 JavaScript中使用msgpack-lite 和zlib实现大数据文件的压缩和读取
  • 医疗连续体机器人模块化控制界面设计与Python库应用研究(中)
  • 【数据库】Redis详解:内存数据库与缓存之王
  • OpenCV 图像处理实战:从图像金字塔到直方图分析
  • MongoDB 安全加固:构建企业级纵深防御体系——用户权限管理与 TLS 加密配置详解
  • 为什么苹果签名经常会掉签?
  • http basic认证流程
  • Docker 存储卷(Volume)核心概念、类型与操作指南
  • 【iOS】 单例模式
  • Matlab机器人工具箱使用4 蒙特卡洛法绘制工作区间
  • 【华为OD】环中最长子串2
  • 08 docker搭建大数据集群
  • 【华为OD】微服务的集成测试
  • Tool | UI/BI类网址收录
  • 计算机视觉(opencv)——基于模板匹配的身份证号识别系统
  • 腾讯推出AI CLI工具CodeBuddy,国内首家同时支持插件、IDE和CLI三种形态的AI编程工具厂商
  • 前后端联调时出现的一些问题记录
  • 网络编程;套接字;TCP通讯;UDP通讯;0909
  • 最后一公里文件传输难题Localsend+cpolar破解
  • Windows 命令行:cd 命令3,当前目录,父目录,根目录
  • 医疗连续体机器人模块化控制界面设计与Python库应用研究(下)
  • Nginx 优化与防盗链
  • Spring Web 异步响应实战:从 CompletableFuture 到 ResponseBodyEmitter 的全链路优化
  • Linux基础命令使用
  • 第二章、PyTorch 入门笔记:从张量基本操作到线性回归实战
  • 【参数详解与使用指南】PyTorch MNIST数据集加载
  • Ruoyi-vue-plus-5.x第六篇Web开发与前后端交互: 6.4 WebSocket实时通信
  • vlan(局部虚拟网)