资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
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<=1012,每个石子的重量小于等于109,且非负
想法是用i、j来依次遍历,i为前k1个小于S的石头首指针,j为后k2个小于S的石头的首指针,最后取k1和k2的最小值
代码如下:
#include<iostream> using namespace std; int main() { long long N, S, maxk = 0; cin >> N >> S; int* W = new int[N]; for (int i = 0; i < N; i++) { cin >> W[i]; } for (int i = 0; i < N; i++) { long long k1 = 0, k2 = 0; long long weight1 = 0, weight2 = 0; int j, k; for (j = i; j < N; j++) { weight1 += W[j]; k1++; if (weight1 > S) { k1--; break; } } for (k = j; k < N; k++) { weight2 += W[k]; k2++; if (weight2 > S) { k2--; break; } } maxk = max(max(k1, k2) / 2, maxk); maxk = max(min(k1, k2), maxk); } cout << 2 * maxk << endl; return 0; }
上述代码只能得20分,很明显第2、3中样例都过不了,会超时,就只能想办法改进,很容易想到我们每次遍历获取和值时很耗费时间,而且很明显与前一个有重复的地方,就可以开一个数组来做前缀和。
并且转变了想法,不采用遍历,采用二分查找找符合S的区间,果然问题豁然开朗了
二分法一般适用于所找的值在一个区间
这里数组从1开始是为了方便之后对于求mid前多少个和,因为初始化将Sum[0]初始化为0
那么前mid个数之和(包括i)可以直接表示为
Sum[i]-Sum[i-mid]
i后mid个数之和可以表示为
S[mid+i]-S[i]
#include<iostream> #include<string.h> using namespace std; int check(long long mid,long long N,long long S,long long *Sum) { for (int i = mid; i <= N - mid; i++) { if (Sum[i] - Sum[i - mid] <= S && Sum[i + mid] - Sum[i] <= S) { return 1; } } return 0; } int main() { long long N, S; cin >> N >> S; long long* W = new long long[N+1]; long long* Sum = new long long[N+1];//前缀和 memset(W, 0, sizeof(W)); memset(Sum, 0, sizeof(Sum)); for (int i = 1; i <= N; i++) { cin >> W[i]; Sum[i] = Sum[i - 1] + W[i]; } long long l = 1, r = N; while (l < r) { long long mid = (l + r + 1) >> 1; if (check(mid, N, S, Sum)) { l = mid; } else { r = mid - 1; } } cout << 2 * l << endl; return 0; } /* 8 3 1 1 1 1 1 1 1 1 8 3 1 2 3 4 5 6 7 8 */
这个题真的困扰我很久。。。。可能是我太菜了