合唱团

题目描述
有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?

输入描述:

每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。

输出描述:

输出一行表示最大的乘积。

代码:

import java.util.Scanner;

public class Main{

    public int number;
    public int[] values;
    public int k;
    public int d;

    public long[][] record;

    public Main(int n){
        number = n;
        values = new int[n];
    }

    public long cal(){
        record = new long[k*2][number];
        //初始化边界
        for(int i=0;i<number;i++){
            record[0][i] = values[i];
            record[1][i] = values[i];
        }

        for(int i=2;i<k*2;i+=2){
            for(int j=0;j<i;j++){
                record[i][j] =0;
                record[i+1][j] =0;
            }
        }

        if(k == 1){
            long max =0;
            for(int j=0;j<number;j++){
                if(record[0][j]>max)
                    max = record[0][j];
            }
            return max;
        }else {

            for(int i=2;i<k*2;i+=2){
                for(int j=0;j<number;j++){
                    long max = 0;
                    long min =0;
                    for(int m=0<(j-d)?(j-d):0;m<j;m++){
                        if(record[i-1][m]<min)
                                min = record[i-1][m];
                        if(record[i-2][m]>max)
                                max = record[i-2][m];

                    }
                    //System.out.println("I:"+i+"max:"+max+"min:"+min);
                    if(record[0][j]>0){
                        record[i][j] = max*record[0][j];
                        record[i+1][j] = min*record[0][j];
                    }else {
                        record[i+1][j] = max*record[0][j];
                        record[i][j] = min*record[0][j];
                    }

                }
            }
            long max = 0;
            for(int j=0;j<number;j++){
                if(record[k*2-1][j]>max)
                    max = record[k*2-1][j];
                if(record[k*2-2][j]>max)
                    max = record[k*2-2][j];
                //System.out.println(record[k*2-2][j]+"+"+record[k*2-1][j]);
            }
            return max;
        }

    }

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        Main test = new Main(n);
        for(int i=0;i<n;i++){
            test.values[i] = scanner.nextInt();
        }
        test.k = scanner.nextInt();
        test.d = scanner.nextInt();
        System.out.println(test.cal());
    }

}

思路:

典型的动态规划问题,从后向前推:假定队列最后一名同学被挑选上,且此同学的法力值为正数时,则之前被挑选上的同学应当有k-1个,且这k-1名同学的法力值乘积应当是他前面所有同学中乘积最大的。(前提:满足第k-1名同学距离第k名同学的距离小于给定值d)
由于法力值有正有负,故需要维护两个记录数组,分别记录最大值与最小值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值