PAT甲级1044 Shopping in Mars (25 分) 记录

题目
参考博客


思路分析:
首先的想法就是暴力求解,也就是遍历任意两点之间的元素和,找到最小的和。但是直觉告诉我这样做肯定会超时,所以我根本没写。

可以怎么改进?暴力解应该是O(n^3)的复杂度,其中有一轮循环是遍历i ~ j之间的元素。这一部分可以简化:在读入数据时顺便维持一个数组arr,该数组的每个元素存放从序列开头到该位置的元素和,这样i ~ j之间的元素和就可以直接用arr[j] - arr[i]求得。这样复杂度应该变为O(n ^ 2 + n) = O(n ^ 2)

其实一般我能想到这里我就满足了,但是仍然可以继续优化。

之前的思路是,对每一个ij将从i+1遍历到序列末尾,来找到最接近m的那个j这其实就是个查找的过程,而查找我们知道,如果能用二分查找而不是线性遍历来查找,那么又会降低复杂度。而这里刚好满足二分查找的条件:arr数组是递增的。这样一来,寻找合适的j就可以用二分查找来代替,复杂度应变为O(nlogn + n)


代码象征性贴一下,来自柳神和开头的博客:

#include<iostream>
#include<vector>
const int MAX = 100001;
using namespace std;

int arr[MAX], des[MAX];

int findBestSum(int i, int n, int m) {
	int left = i + 1;
	int right = n;
	int mid;
	//为什么能用二分查找?因为arr数组是递增的
	while (left < right) {
		mid = (left + right) / 2;
		if (arr[mid] - arr[i] >= m) {
			right = mid;
		}
		else left = mid + 1;
	}
	des[i] = right;
	return arr[right] - arr[i];
}

int main() {
	int n, m;
	cin >> n >> m;
	int i, j;
	arr[0] = 0;//0处不存有效值
	for (i = 1; i <= n; i++) {
		cin >> arr[i];
		arr[i] += arr[i - 1];
	}
	vector<int> vec;
	int res, mm = 0x7fffffff;
	for (int i = 0; i < n; i++) {
		res = findBestSum(i, n, m);
		if (res >= m) {
			if (res == mm) {
				vec.push_back(i);
			}
			else if (res < mm) {
				mm = res;
				vec.clear();
				vec.push_back(i);
			}
		}
		else {
			break;
		}
	}
	for (i = 0; i < vec.size(); i++) {
		printf("%d-%d\n", vec[i] + 1, des[vec[i]]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值