蓝桥杯试题-算法训练 礼物

452 阅读2分钟

「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战

今天要说的主要是一个蓝桥杯的题目。

题目

image.png

题目上说是那个贪心,但是我没想到那个什么贪心,解法。最后是用二分法求解的。 看题目的意思其实很简单,拿出偶数个连续的石头,然后满足那个质量关系,之后我们直接创建一个sum数组 那么问题就变成了,找一个有序数组当中对称部分的差小于或者等于S的问题。

问题分析

竟然我们转化了这个问题,那么现在来分析一下如何处理,很容易想到的就是那个二分法,如果右边的差值大,那么在中间往右不存在那个S,然后缩小范围,之后解答。我们只需要在运行程序的时候注意代码判断边界即可。

之后是那个输入问题,那个数量大,并且直接使用int越界。

image.png

所以注意使用long即可

编码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.StringTokenizer;

class Main {

    static int N;
    static long S;
    static long[] Stones;
    static long[] StonesSumWeight;
    public static void main(String[] args) throws IOException {
        Reader.init(System.in);
        N = Reader.nextInt();
        S = Reader.nextLong();

        //从下标1开始方便我找元素,此外为了避免重复运算先计算所有的质量和
        Stones = new long[N + 1];
        StonesSumWeight = new long[N + 1];
        for(int i=1;i<=N;i++){
            Stones[i]=Reader.nextLong();
            StonesSumWeight[i] = StonesSumWeight[i-1]+Stones[i];
        }
        //我们题目要求的是2*k个石头,其实就是偶数
        //问题变成了我们在StoneSunWeight里面找到左右两边的差值不大于S的,如果没有
        //找到那个差值说明太大了,所以直接缩短一般距离。
        int left = 1;
        int right = N;
        while (left<right){
            int mid = (right+left+1)>>1;
            if(IsFun(mid)){
                left = mid;
            }else{
                right = mid-1;
            }
        }
        System.out.println(2*left);

    }


    private static boolean IsFun(int mid) {
        for(int i = mid; i <= (N - mid); i++) {
            if(StonesSumWeight[i] - StonesSumWeight[i - mid] <= S && StonesSumWeight[i + mid] - StonesSumWeight[i] <= S) {
                return true;
            }
        }
        return false;
    }

}


class Reader {
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    /**
     * call this method to initialize reader for InputStream
     */
    static void init(InputStream input) {
        reader = new BufferedReader(
                new InputStreamReader(input));
        tokenizer = new StringTokenizer("");
    }

    /**
     * get next word
     */
    static String next() throws IOException {
        while (!tokenizer.hasMoreTokens()) {
            //TODO add check for eof if necessary
            tokenizer = new StringTokenizer(
                    reader.readLine());
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    static long nextLong() throws  IOException{
        return Long.parseLong(next());
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
}