蓝桥杯——数组切分(JAVA)

题目:

已知一个长度为 N 的数组:A1​,A2​,A3​,…AN​ 恰好是 1∼N 的一个排列。现 在要求你将 A 数组切分成若干个 (最少一个, 最多 N 个) 连续的子数组, 并且 每个子数组中包含的整数恰好可以组成一段连续的自然数。

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

1324 : 每个单独的数显然是 (长度为 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.

运行限制

  • 最大运行时间:5s
  • 最大运行内存: 512M

代码: 

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();                //储存元素个数
        int [] A=new int[n+1];            
        for (int i=1;i<n+1;i++){
            A[i]=sc.nextInt();
        }
        int[] dp=new int[n+1];     //前n个元素之前有几种切分方法
        dp[0]=1;              //初始化

        for (int r=1;r<n+1;r++){      
            int max=Integer.MIN_VALUE;
            int min=Integer.MAX_VALUE;
            for (int l=r;l>0;l--){        //从后往前遍历
                max=Math.max(A[l],max);
                min=Math.min(A[l],min);
                if (max-min==r-l){
                    dp[r]=(dp[r]+dp[l-1])%1000000007;  //状态转移
                }

            }
        }
        System.out.println(dp[n]);
        sc.close();

    }
}

思路:本题采用了动态规划的思路。

首先从题目中得知划分出来的数组是连续的,所以一段数组中的max-min就应该等于数组中最右端的下标减去最左端的下表。

max-min=r-l

接着我们从数组的第一个元素开始找前i个元素,有几种划分方式。依次向后dp。得到状态转移方程

 dp[r]=dp[r]+dp[l-1]

 dp要有两个循环,第一层循环相当于确定了最右边的元素,然后依次向左遍历,找到可以组成连续子序列时再加上最左边元素之前所有元素的划分方式。依次向前直到第一个元素。

第二层循环必须从后往前遍历,因为我们要找最大最小值(从后往前一个数一个数找,可以保证找到的最值一定正确),如果从前往后遍历(拿第一次也就是遍历第一个元素时)最大最小值都是第一个元素,但此时的子序列是从第一个元素到r中间元素都没有进行比较,就会出现错误。

dp[0]=1,我是这么理解的:当后面前n个元素可以组成一个连续子序列时,前面有0个元素只有自身一种情况。比如例题中 1 3 2 4  前3中所有元素可以组成一个连续子序列,没有剩余元素了所以只有自身这一种情况。   也就是说没有元素也是合法情况。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值