礼物
问题描述
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值。