PAT.1044 Shopping in Mars - 前缀和+二分查找
题目链接
这道题让我们在给定的数列找找到和为某个值的子序列,并按左界升序输出,如果不存在这样的子序列,就按左界升序输出和大于且最接近给定值的子序列。
首先想到可以用前缀和来预处理数据,然后枚举左右界检查和是否符合条件。
然后呢?
然后发现这样会超时,仔细一看题干,限时300ms。
没办法,既然前缀和本身是递增的(给定数列所有数为正数),所以可以枚举左界然后对右界进行二分查找。
题解
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,target,nearestSum = 0x3f3f3f3f,vals[100005],preSum[100005];
bool findSum = false;
void binarySearch(int leftBound,int targetSum){
int l = leftBound,r = n;
while(l <= r){
int mid = (l + r) / 2;
int sum = preSum[mid] - preSum[leftBound];
if(sum > targetSum){
if(!findSum) nearestSum = min(nearestSum,sum);
r = mid - 1;
}else if(sum < targetSum){
l = mid + 1;
}else{
findSum = true;
cout<<leftBound + 1<<'-'<<mid<<endl;
break;
}
}
}
int main(){
scanf(" %d %d",&n,&target);
for(int i = 1 ; i <= n ; ++i){
scanf(" %d",vals + i);
preSum[i] = preSum[i - 1] + vals[i];
}
for(int i = 0 ; i <= n ; ++i) binarySearch(i,target);
if(!findSum){
for(int i = 0 ; i <= n ; ++i) binarySearch(i,nearestSum);
}
}