数组切分【Java蓝桥杯】

第十三届蓝桥杯大赛软件赛省赛 Java 大学 B 组


试题 G: 数组切分

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分

题目

【问题描述】

已知一个长度为 N 的数组:A1, A2, A3, …AN 恰好是 1 ∼ N 的一个排列。

现在要求你将 A 数组切分成若干个 (最少一个,最多 N 个) 连续的子数组,

并且 每个子数组中包含的整数恰好可以组成一段连续的自然数。

例如对于 A = {1, 3, 2, 4}, 一共有 5 种切分方法:

{1}{3}{2}{4}:每个单独的数显然是 (长度为 1 的) 一段连续的自然数。

{1}{3, 2}{4}:{3, 2} 包含 2 到 3,是 一段连续的自然数,另外 {1} 和 {4} 显然 也是。

{1}{3, 2, 4}:{3, 2, 4} 包含 2 到 4,是 一段连续的自然数,另外 {1} 显然也是。

{1, 3, 2}{4}:{1, 3, 2} 包含 1 到 3,是 一段连续的自然数,另外 {4} 显然也是。

{1, 3, 2, 4}:只有一个子数组,包含 1 到 4,是 一段连续的自然数。

【输入格式】

第一行包含一个整数 N。第二行包含 N 个整数,代表 A 数组。

【输出格式】

输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取 模后的值

【样例输入】

4 1 3 2 4

【样例输出】

5

【评测用例规模与约定】

对于 30% 评测用例,1 ≤ N ≤ 20. 对于 100% 评测用例,1 ≤ N ≤ 10000.

代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class Main {
	private static long cnt = 0;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int[] arr = new int[n];
		for(int i = 0;i < arr.length;i++) {
			arr[i] = sc.nextInt();
		}
		fun(arr, "", 1);
		System.out.println(cnt % 1000000007);	
	}
	public static void fun(int[] arr,String str,int c) {
		if(c > arr.length) {
			String[] group = str.split(";");
			for(String string : group) {
				String[] nums = string.split(",");
				ArrayList<Integer> list = new ArrayList<>();
				for(String num : nums) {
					if(num != "") 
						list.add(Integer.valueOf(num));
				}
				Collections.sort(list);
				for(int i = 1;i < list.size();i++) {
					if(list.get(i) - list.get(i - 1) != 1) {
						return;
					}
				}
			}
			cnt++;
		}else {
			str += arr[c - 1] + ",";
			fun(arr, str + ";", c + 1);
			if(c != arr.length) {
				fun(arr, str, c + 1);
			}
		}
	}
}

小结

  1. public class Main {
    	private static long cnt = 0;    //cnt ~ 结果
    	public static void main(String[] args) {
    		Scanner sc = new Scanner(System.in);
    		int n = sc.nextInt();
    		int[] arr = new int[n];
    		for(int i = 0;i < arr.length;i++) {
    			arr[i] = sc.nextInt();
    		}
    		fun(arr, "", 1);
    		System.out.println(cnt % 1000000007);	
    	}
        /*
        arr ~ 源数组
        str ~ 获取arr中各元素,并通过增加“,”“;”以分组
        c ~ 层数,判断是否终止调用
        */
    	public static void fun(int[] arr,String str,int c) {
    		if(c > arr.length) {
    			String[] group = str.split(";");	//若干个子数组group
    			for(String string : group) {
    				String[] nums = string.split(",");	//子数组中包含的各整数nums
    				ArrayList<Integer> list = new ArrayList<>();
    				for(String num : nums) {
    					if(num != "") 
    						list.add(Integer.valueOf(num));
    				}
    				Collections.sort(list);	//排序,以判断是否是“连续的自然数”
    				for(int i = 1;i < list.size();i++) {
    					if(list.get(i) - list.get(i - 1) != 1) {
    						return;	//不符合情况,返回
    					}
    				}
    			}
    			cnt++;	//满足题意,结果加一
    		}else {
    			str += arr[c - 1] + ",";	//获取各整数
    			fun(arr, str + ";", c + 1);	//在此处分组,并递归
    			if(c != arr.length) {	//当取得最后一个整数时,所谓在此处分组,不分组是同一种情况,故略去其中一个
    				fun(arr, str, c + 1);	//在此处不分组,并递归
    			}
    		}
    	}
    }
    
  2. 好傻啊我,当时以为有数学规律,列了一大堆,终是没发现

  3. 代码应该还可以再优雅些,暂时就这样吧,看多写多了,就会好些

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值