数组分割(2023省蓝桥杯)n种讨论 JAVA

目录

  • 1、题目描述:
  • 2、前言:
  • 3、动态规划(bug):
  • 3、递归 + 剪枝(超时):
  • 4、数学(正解):

1、题目描述:

小蓝有一个长度为 N 的数组 A = [A0, A1,…, AN−1]。现在小蓝想要从 A 对应的数组下标所构成的集合 I = {0, 1,
2, . . . , N − 1} 中找出一个子集 R1,那么 R1在 I 中的补集为 R2。记 S1=∑r∈R1Ar,S2
=∑r∈R2Ar,我们要求 S1 和 S2 均为偶数,请问在这种情况下共有多少种不同的 R1。当 R1 或 R2 为空集时我们将 S1 或 S2 视为 0。 输入格式 第一行一个整数 T,表示有 T 组数据。 接下来输入 T 组数据,每组数据包含两行:第一行一个整数 N,表示数组
A 的长度;第二行输入 N 个整数从左至右依次为 A0, A1, . . . , AN−1,相邻元素之间用空格分隔。 输出格式
对于每组数据,输出一行,包含一个整数表示答案,答案可能会很大,你需要将答案对1000000007 进行取模后输出。

样例输入:

2
2
6 6
2
1 6

样例输出:

4
0

[提示]
对于第一组数据,答案为 4。(注意:大括号内的数字表示元素在数组中的下标。)
R1 = {0}, R2 = {1};此时 S1 = A0 = 6 为偶数, S2 = A1 = 6 为偶数。
R1 = {1}, R2 = {0};此时 S1 = A1 = 6 为偶数, S2 = A0 = 6 为偶数。
R1 = {0, 1}, R2 = {};此时 S1 = A0 + A1 = 12 为偶数, S2 = 0 为偶数。
R1 = {}, R2 = {0, 1};此时 S1 = 0 为偶数, S2 = A0 + A1 = 12 为偶数。
对于第二组数据,无论怎么选择,都不满足条件,所以答案为 0。

对于 20% 的评测用例,1 ≤ N ≤ 10。
对于 40% 的评测用例,1 ≤ N ≤ 10^2。
对于 100% 的评测用例,1 ≤ T ≤ 10, 1 ≤ N ≤ 103 , 0 ≤ Ai ≤ 10^9。


2、前言:

这题考完蓝桥杯之后,自闭地看着答案整理过一遍,当时一度认为只能用数学方法做,而且当时也意识到自己见识太少,所以这俩月一直在埋头苦刷暂避锋芒。这不,这两天感觉自己又行了再来回顾本题,看看能否用新的算法做,以下是思考结果:


3、动态规划(bug):

最开始想到的就是用动态规划解决本题,虽然动态规划学的不熟,但是有思路就能写出来,本题还是不建议用动态规划解因为题目给的数据太大,非常容易爆数组。

1、本题与01背包有些许相似所以用01背包思想试解

2、dp[ i ][ j ] = n即:考虑前i个元素挑选出的元素和为j的方案数为n

3、初始化dp[i][0] = 1,考虑前i个元素,和为0的方案数为什么都不选1种

4、对于元素i无非选与不选两种,dp[i][j]=dp[i - 1][j] + dp[i - 1][j - nums[j]],前提是j >= nums[j]

5、最后取所有dp[len][j]且j是偶数的元素即可

错误代码1:

import java.util.*;

public class Text2{//继承父类Jframe,获取父类方法
	public static int mod = 1000000007;
    public static void main(String[] args) {
    	  Scanner sc = new Scanner(System.in);
    	  int n = sc.nextInt();
    	  for(int i = 0; i < n; i ++) {
    		  int len = sc.nextInt();
    		  int nums[] = new int[len + 1];
    		  for(int j = 1; j <= len; j ++) nums[j] = sc.nextInt();
    		   
    		  System.out.println(dfs(nums, len));
    		 
    	  }
    }
    
   public static int dfs(int nums[], int len) {
	  int num = 0;
	  for(int j = 1; j <= len; j ++) num = num + nums[j];
	  if(num % 2 != 0) return 0;
	  int dp[][]  = new int[len + 1][num + 1];
	  for(int i = 0; i <= len; i ++) dp[i][0] = 1;
	  int cnt = 1;
	  for(int i = 1; i <= len; i ++) {
		  for(int j = 1; j <= num; j ++) {
			  
			  dp[i][j] = dp[i - 1][j]; 
			  
			  if(j >= nums[i])
				  dp[i][j] = dp[i][j] + dp[i - 1][j - nums[i]];
			  
			  if(i == len && j % 2 == 0) {
				  cnt = cnt + dp[i][j];
			      System.out.println(i + " " + j + " " + dp[i][j]);
			  }
		  }
	  }
	  return cnt;
   }
    
}

想着用一维数组优化
错误代码1优化版:

import java.util.*;

public class Text1{//继承父类Jframe,获取父类方法
	public static int mod = 1000000007;
    public static void main(String[] args) {
    	  Scanner sc = new Scanner(System.in);
    	  int n = sc.nextInt();
    	  for(int i = 0; i < n; i ++) {
    		  int len = sc.nextInt();
    		  int nums[] = new int[len + 1];
    		  for(int j = 1; j <= len; j ++) nums[j] = sc.nextInt();
    		   
    		  System.out.println(dfs(nums, len));
    		 
    	  }
    }
    
   public static int dfs(int nums[], int len) {
	  int num = 0;
	  for(int j = 1; j <= len; j ++) num = num + nums[j];
	  if(num % 2 != 0) return 0;
	  int dp[]  = new int[num + 1];
	  dp[0] = 1;//考虑前0件元素得到0的方法有1个
	  int cnt = 1;
	  for(int j = 1; j <= len; j ++)//考虑前len个元素
		  for(int z = num; z >= nums[j]; z --)
			  {
			   dp[z] = dp[z] + dp[z - nums[j]];
			   if(j == len && z % 2 == 0 && (num - z) % 2 == 0) cnt = (cnt + dp[z]) % mod;
			  }
	  return cnt;
   }
    
}

解题思路:

为什么看着思路没问题题,但却还是错误代码呢,因为题目的数据含有0!!!

以正常没有0的[2, 4]为例子:

在这里插入图片描述

动态规划需要通过数组迭代,对于元素i无非就是选与不选但当元素nums[i] = 0的时候,选了与没选是不确定的其无法从初始dp[0][0]迭代过来以有0的[0, 2]为例子:

在这里插入图片描述
元素无法从dp[0][0]迭代出去,形成了不通路。

值得一提的是优化代码错误更多

以[2, 2, 4]为例,未优化与优化代码数组迭代过程如下:

在这里插入图片描述

由于一维数组从后往前遍历dp[3][2]虽然符合条件但是无法从dp[2][2]迭代下来(2 < 4)

如果数据范围>0的话动态规划还是能在不爆数组的情况下都对的以下是产生随机数据的代码以及测试结果

代码:

import java.awt.print.Printable;
import java.util.*;

public class Text4{
	public static int mod = 1000000007;
    public static void main(String[] args) { 
    	      for(int i = 0; i < 1000; i ++) {
    	    	Scanner sc = new Scanner(System.in);
    		    int len = new Random().nextInt(1000) + 1;
//    	    	int len = sc.nextInt();
    		    int nums[] = new int[len + 1];
    		    for(int j = 1; j <= len; j ++) 
//    		    	nums[j] = sc.nextInt();
    		    	nums[j] = new Random().nextInt(1000) + 1;
    		    
    		    boolean flag =  (dfs(nums, len) == ddffs(nums, len));
    		    System.out.println(flag);
    		    if(!flag) {
    		    	print(nums, dfs(nums, len), ddffs(nums, len));
    		    	return;
    		    }
    	      }
    }
   public static int dfs(int nums[], int len) {
	   int num = 0;
		  for(int j = 1; j <= len; j ++) num = num + nums[j];
		  if(num % 2 != 0) return 0;
		  int dp[][]  = new int[len + 1][num + 1];
		  for(int i = 0; i <= len; i ++) dp[i][0] = 1;
		  int cnt = 1;
		  for(int i = 1; i <= len; i ++)
			  for(int j = 1; j <= num; j ++) {
				  
				  dp[i][j] = dp[i - 1][j]; 
				  if(j >= nums[i])
					  dp[i][j] = (dp[i][j] + dp[i - 1][j - nums[i]]) % mod;
				  
				  if(i == len && j % 2 == 0) cnt = (cnt + dp[i][j]) % mod;
			  }
		  
		  return cnt;
   }
   public static int ddffs(int a[], int m) {
	     int L = 0, J = 0; 
		 for(int i = 1; i <= m; i ++) 
			 if(a[i] % 2 == 0) L ++;
			 else J ++;
		 
		 if(J % 2 != 0) return 0;
		 else {
			 if(J == 0) J = 1;
			 return (int)(Math.pow(2, L) * Math.pow(2, J - 1) % mod);
		 }
 }
   public static void print(int a[], int b, int c) {
	   System.out.println(a.length - 1 + " " + b + " " + c);
	   for(int i = 1; i < a.length; i ++) System.out.print(a[i] + " ");
   }
}

在这里插入图片描述

好动态规划到此宣布破产


3、递归 + 剪枝(超时):

考试的时候就是用递归做的,但是太傻比了,退出条件不对,我早就应该知道递归的每条路径就是一种遍历情况,当时以及昨天我却在分枝上找答案太傻逼了,答案应该在递归末尾节点找。

在这里插入图片描述
太傻比了之前用递归一直是在分支上找答答案,跟本没啥意义,再加上有0的出现我一直以为本题不能用常规递归做,用什么分治思想之类的。。。刚在才醒悟过来,把递归图画了以下才醒悟,根本没必要那么复杂直接在递归末尾节点判断就行了

每个元素都是选与不选两种情况,从首节点到任意末尾节点都是一条路径,本题来说是选元素的其中一种选法,只需要判断满不满足题意就行了,太傻比了希望以后不要再犯这种错误了!

代码:

import java.util.Scanner;

public class Text6 {//继承父类Jframe,获取父类方法
	public static int mod = 1000000007;
    public static void main(String[] args) {
    	  Scanner sc = new Scanner(System.in);
    	  int m = sc.nextInt();
    	  for(int j = 0; j < m; j ++) {
    		  long sum = 0;
    	   int n = sc.nextInt();
    	   int nums[] = new int[n];
    	  
    	   for(int i = 0; i < n; i ++) {
    		   nums[i] = sc.nextInt();
    	       sum = sum + nums[i];
    	   }
    	   if(sum % 2 == 0)
    	     System.out.println(dfs(nums, n, 0, 0));
    	   else
    		   System.out.println(0);
    	  }
    }
    
   public static int dfs(int nums[], int len, int i, long sum) {
	    if(i == len) {
	    	if(sum % 2 == 0) return 1;
	    	return 0;
	    }
	    int choosethis = dfs(nums, len, i + 1, sum + nums[i]) % mod;
	    int notchoose = dfs(nums, len, i + 1, sum) % mod;
	    return (choosethis + notchoose) % mod;
   }
    
}

在这里插入图片描述
超时是意料之内,剪一下枝即可

优化代码:

用二维数组可能会爆掉,用大杀器其map应该就能拿下本题:

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Text7 { 
	public static Map<String, Integer> map;
	public static int mod = 1000000007;
    public static void main(String[] args) {
    	  Scanner sc = new Scanner(System.in);
    	  int m = sc.nextInt();
    	  for(int j = 0; j < m; j ++) {
    		  map = new HashMap<String, Integer>();
    		  long sum = 0;
    	      int n = sc.nextInt();
    	      int nums[] = new int[n];
    	  
    	      for(int i = 0; i < n; i ++) {
    		     nums[i] = sc.nextInt();
    	         sum = sum + nums[i];
    	     }
    	   if(sum % 2 == 0)
    	     System.out.println(dfs(nums, n, 0, 0));
    	   else
    		   System.out.println(0);
    	  }
    }
    
   public static int dfs(int nums[], int len, int i, long sum) {
	    if(map.containsKey(i + " " + sum)) return map.get(i + " " + sum);
	    if(i == len) {
	    	if(sum % 2 == 0) return 1;
	    	return 0;
	    }
	    
	    int choosethis = dfs(nums, len, i + 1, sum + nums[i]) % mod;
	    int notchoose = dfs(nums, len, i + 1, sum) % mod;
	    map.put(i + " " + sum, (choosethis + notchoose) % mod);
	    return (choosethis + notchoose) % mod;
   }
    
}

看一下成果!

在这里插入图片描述
我真是热烈的🐎测了好几遍一个样,要么测试的地方不行,要么map查表和剪纸的部分正负得零,反正麻了

算了不重要了,最后再说一下为什么递归不会被0影响,这从递归图可以看出来

在这里插入图片描述
递归每条路径都是一个选择情况,即使两个0也可以清楚看出所有情况。


4、数学(正解):

详细解析在这里:
2023年第十四届蓝桥杯JavaB组省赛真题及解析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/89263.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 密码破解指南:10~14

协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【OpenDocCN 饱和式翻译计划】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 收割 SB 的人会被 SB 们封神&#xff0c;试图唤醒 SB 的人是 SB 眼中的 SB。——SB 第三定律 十、加…

docker 04(docker 应用部署)

一、部署Mysql 需求: 在Docker容器中部署MySQL&#xff0c;并通过外部mysql客户端操作MySQLServer。 二、部署tomcat 三、部署nginx 四、部署redis

数据结构(2)

冒泡排序&#xff1a; 1.比较相邻的两个元素。如果前一个元素比后一个元素大&#xff0c;则交换两者位置。 2.对每一对相邻元素做相同工作&#xff0c;从第一对元素到最后一对元素&#xff0c;最后的一个元素就是最大的元素。 for(int ia.length-1;i>0;i--){for (int j 0…

c语言练习题28:杨氏矩阵

杨氏矩阵 从左到右增加 从上到下增加 思路&#xff1a; 代码&#xff1a; #include<stdio.h> int findNum(int(*arr)[3], int x, int y, int k) {int i 0;int j y - 1;while (i<x&&j>0) {if (arr[i][j] > k) {j--;}else if (arr[i][j] < k) {i;…

Linux上实现分片压缩及解压分片zip压缩包 - 及zip、unzip命令详解

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

SpringBootWeb案例 Part 2

目录 3. 员工管理 3.1 分页查询 3.1.1 基础分页 3.1.1.1 需求分析 3.1.1.2 接口文档 3.1.1.3 思路分析 3.1.1.4 功能开发 PageBean 3.1.1.5 功能测试 3.1.1.6 前后端联调 3.1.2 分页插件{分页查询-PageHelper插件} 3.1.2.1 介绍 官网&#xff1a; 3.1.2.2 代码实…

04-Numpy基础-利用数组进行数据处理

NumPy数组使你可以将许多种数据处理任务表述为简洁的数组表达式&#xff08;否则需要编 写循环&#xff09;。用数组表达式代替循环的做法&#xff0c;通常被称为矢量化。一般来说&#xff0c;矢量化 数组运算要比等价的纯Python方式快上一两个数量级&#xff08;甚至更多&…

【核磁共振成像】方格化重建

目录 一、缩放比例二、方格化变换的基础三、重建时间四、方格化核 一、缩放比例 对于笛卡尔K空间直线轨迹数据可直接用FFT重建&#xff0c;而如果K空间轨迹的任何部分都是非均匀取样的 可用DFT直接重建&#xff0c;有时称为共轭相位重建&#xff0c;但此法太慢不实用。把数据再…

在VS中使用格式化工具

在VS中使用格式化工具 官网地址: https://clang.llvm.org/ 最后更新时间&#xff1a;2023.8.25 这里以windows为例&#xff0c;使用的环境为VS。 &#xff08;一&#xff09;下载安装LLVM 下载地址: https://github.com/llvm安装&#xff08;自己选择安装路径&#xff09; &…

伦敦金走势图行情值得关注

不知道大家是否了解过伦敦金这个投资品种&#xff0c;或者有否财经网站以及金融终端上看到过它的行情走势图。其实&#xff0c;伦敦金并不是一种实实在在的黄金&#xff0c;而是一种跟踪伦敦现货黄金市场价格走势的黄金保证金交易品种&#xff0c;它每天的行情走势变化&#xf…

安科瑞AMB300系列母线槽红外测温解决方案监测母线槽连接处温度-安科瑞黄安南

一、行业背景 随着当今社会的发展和用电量的急剧上升&#xff0c;现代化工程设施和装备的涌现&#xff0c;封闭式母线即母线槽因方便、节能、载流量大、机械强度高 、安装灵活、寿命长等特点&#xff0c;逐渐取代传统电缆&#xff0c;广泛应用于室内变压站、高层建筑和大型厂房…

基于spring boot校园疫情信息管理系统/疫情管理系统

摘要 随着计算机技术&#xff0c;网络技术的迅猛发展&#xff0c;Internet 的不断普及&#xff0c;网络在各个领域里发挥了越来越重要的作用。特别是随着近年人民生活水平不断提高&#xff0c;校园疫情信息管理系统给学校带来了更大的帮助。 由于当前疫情防控形势复杂&#xff…

2023年国赛 高教社杯数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…

RTSP/Onvif视频服务器EasyNVR安防视频云服务调用接口录像会被自动删除的问题解决方案

EasyNVR安防视频云服务是基于RTSP/Onvif协议接入的视频平台&#xff0c;可支持将接入的视频流进行全平台、全终端的分发&#xff0c;分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等。平台丰富灵活的视频能力&#xff0c;可应用在智慧校园、智慧工厂、智慧水利等…

使用ELK(ES+Logstash+Filebeat+Kibana)收集nginx的日志

文章目录 Nginx日志格式修改配置logstash收集nginx日志引入Redis收集日志写入redis从redis中读取日志 引入FilebeatFilebeat简介Filebeat安装和配置 配置nginx转发ES和kibanaELK设置账号和密码 书接上回&#xff1a;《ELK中Logstash的基本配置和用法》 Nginx日志格式修改 默认…

编写Dockerfile制作自己的镜像并推送到私有仓库

说明&#xff1a;我将用到的私有仓库是Harbor&#xff0c;安装教程参考我的这一篇文章&#xff1a; 安装搭建私有仓库Harbor_Word_Smith_的博客-CSDN博客 一、案例1 1、要求 编写Dockerfile制作Web应用系统nginx镜像&#xff0c;生成镜像nginx:v1.1&#xff0c;并推送其到私…

资深网络工程师的网络排障全过程,太强了!【附工具下载】

下午好&#xff0c;我的网工朋友 我们知道&#xff0c;交换机是局域网中一种很重要的网络设备&#xff0c;它的工作状态与客户端系统的上网状态息息相关。 可是&#xff0c;在实际工作过程中&#xff0c;交换机的状态很容易受到外界的干扰&#xff0c;那样一来局域网中就会出…

wazuh

1.wazuh的作用 Wazuh 是一个免费的开源安全平台&#xff0c;统一了 XDR 和 SIEM 功能。它可以保护本地、虚拟化、容器化和基于云的环境中的工作负载。Wazuh 帮助组织和个人保护其数据资产免受安全威胁。它被全球数千个组织广泛使用&#xff0c;从小型企业到大型企业。 Wazuh的…

物联网(IoT)安全挑战与解决方案: 分析物联网设备面临的安全威胁,以及如何设计和管理安全的IoT生态系统

第一章&#xff1a;引言 随着科技的飞速发展&#xff0c;物联网&#xff08;IoT&#xff09;作为连接世界的桥梁&#xff0c;已经成为现代社会不可或缺的一部分。然而&#xff0c;随着IoT设备数量的不断增加&#xff0c;其安全问题也日益显著。本文将深入探讨IoT领域面临的安全…

opencv 文档识别+UI界面识别系统

目录 一、实现和完整UI视频效果展示 主界面&#xff1a; 识别结果界面&#xff1a; 查看处理图片过程&#xff1a; 查看历史记录界面&#xff1a; 二、原理介绍&#xff1a; 将图像变换大小->灰度化->高斯滤波->边缘检测 轮廓提取 筛选第三步中的轮廓&#xf…