蓝桥杯习题——礼物

礼物

问题描述

JiaoShou在爱琳大陆的旅行完毕,即将回家,为了纪念这次旅行,他决定带回一些礼物给好朋友。在走出了怪物森林以后,JiaoShou看到了排成一排的N个石子。这些石子很漂亮,JiaoShou决定以此为礼物。但是这N个石子被施加了一种特殊的魔法。如果要取走石子,必须按照以下的规则去取。每次必须取连续的2*K个石子,并且满足前K个石子的重量和小于等于S,后K个石子的重量和小于等于S。由于时间紧迫,Jiaoshou只能取一次。现在JiaoShou找到了聪明的你,问他最多可以带走多少个石子。

输入格式

第一行两个整数N、S。
第二行N个整数,用空格隔开,表示每个石子的重量。

输出格式

第一行输出一个数表示JiaoShou最多能取走多少个石子。

样列输入

8 3
1 1 1 1 1 1 1 1

样列输出

6

样列解释

任意选择连续的6个1即可。

数据规模和约定

对于20%的数据:N<=1000
对于70%的数据:N<=100,000
对于100%的数据:N<=1000,000,S<=10^12,每个石子的重量小于等于10^9,且非负

C代码

#include <stdio.h>
#include <stdlib.h>

//判断在当前长度k下,是否存在可行解。
//存在返回1,不存在返回0
int Judge(long long* arr ,long long k, long long N, long long S);

int main(){
    //读取数据
    //N和S必须为long long,并依次注意输入输出格式
	long long N = 0;
	long long S = 0;
    scanf("%lld %lld",&N,&S);
    long long* arr = (long long*)malloc(sizeof(long long) * (N + 1));
    long long i = 0;
    arr[0] = 0;
    for(i=1;i<=N;i++){
        scanf("%lld",&arr[i]);
        //注意这里记录前缀和,arr[i]记录前i个数的和
        arr[i] = arr[i - 1] + arr[i];
    }

    //二分法计算
    long long left = 1, right = N;
    //这里必须为小于等于!!!(why?)
    //比如当left和right等于2时
    //用left<right程序直接打印4(默认此时出现解)
    //用left<=right打印2(此时找不出解)或4
    while(left <= right){
        //也要注意这里k的选取
        long long k = (left + right) / 2;
        if(Judge(arr ,k , N, S) == 1){
            left = k + 1;
        }
        else{
            right = k - 1;
        }
    }
    
    //注意这里要×2,right最后一定为K最大值(很巧秒)
    printf("%lld", right * 2);
	return 0;
}

int Judge(long long* arr ,long long k, long long N, long long S){
    long long i = k;
    for(;i<=N - k;i++){
        //也要注意这里arr[i]-arr[i-k]和arr[i + k] - arr[i]都是连续k个数的值
        if(arr[i] - arr[i - k] <= S && arr[i + k] - arr[i] <= S)
            return 1;
    }
    return 0;
}

感受

  • 先说过程中出现的问题(很痛苦,很挫败,代码也是借鉴的网上的)
    • 这段代码使用二分法,代码中有许多细节(比如循环条件选取,中间点的选取),脑子不是很清醒,导致长时间的debug;
    • 编程不注意输入输出格式,%lld错误同样导致长时间debug;
  • 平时只在查找和某道找中位数的题目中使用过二分法。这道题使用二分法找题目中的K值,非常巧妙。如果当前K值有满足题意的解,则变大K值;如果没有则变小。逐步逼近最大的K值。
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蝴蝶飞过废墟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值