PAT A1044 Shopping in Mars(***二分法)

问题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805439202443264

题意:

    给出一个数字序列与一个数m,在数字序列中求出所有和值为m的连续子序列(区间下标左端点小的先输出,左端点相同时右端点小的先输出)。若没有这样的序列,求出和值恰好大于m的子序列(即所有和值大于m的子序列中和值最接近m)。假设序列下标从1开始。假设序列下标从1开始。

思路:

    令sum[i]表示A[1] ~A[i]的和值,则sum数组单调递增。连续子序列A[i] ~A[j]的和等于sum[j] - sum[i-1]。因此用二分法寻找sum数组中值大于sum[i-1] + m的元素下标(有sum[j] - sum[i-1] = m)推得,并按要求将合适的数保存在nearm中。并再次循环找sum[j-1] - sum[i-1] = nearm的数组下标。

#include<cstdio>
#include<algorithm>
using namespace std;

int n, m, nearm = 100000010;
int sum[100010];

int main(){

    scanf("%d %d",&n, &m);
	
	sum[0] = 0;
	for(int i = 1; i <= n; i++){
		scanf("%d",&sum[i]);
		sum[i] += sum[i-1];
	}
	
	
//第一个循环,判断是否有和值为 m 的子序列 
//若有,nearm = m; 若没有,求和值恰好大于m的子序列,和值保存在nearm中 
	for(int i = 1; i <= n; i++){
		//在[i,n+1)中找第一个大于sum[i - 1] + m的位置 
		int j = upper_bound(sum + i, sum + n + 1, sum[i - 1] + m) - sum;
		if(sum[j - 1] - sum[i - 1] == m){
			nearm = m;
			break;
		}
		else if(j <= n &&sum[j] - sum[i - 1] < nearm)
		    nearm = sum[j] - sum[i - 1];
	}
	
	for(int i = 1; i <= n; i++){
		//在[i,n+1)中找第一个大于sum[i - 1] + nearm的位置 
		int j = upper_bound(sum + i, sum + n + 1, sum[i - 1] + nearm) - sum;
		if(sum[j - 1] - sum[i - 1] == nearm)
		    printf("%d-%d\n", i, j - 1);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值