51nod 1094

这题主要是有负数,如果没有负数的话我觉得到可以用尺取法做一做、

我这题的思路做一个前缀和并记录那个前缀的末位置,排序前缀和,类似暴力枚举的思路 判断sum[i] - sum[j] = k, 枚举每一个前缀分别是sum[i]还是sum[j]讨论 这里用二分找,我们找到数组里面第一个大于等于这个数的位置,然后依次向前推,看是否满足条件,因为满足的位置可能不止一个所以要向前推,注意这里要保证i最小的情况下j最小,这里还有一些要注意的细节,比如一个数的时候,比如就是前缀和的时候、

#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int qq = 10010;
struct Segment{
	int id;
	long long sum;
	bool operator < (const Segment &a)const{
		return sum<a.sum;
	} 
}seg[qq];
long long dp[qq];
int find(long long x, long long n){
	int l=1, r=n;
	int m;
	while(l<r){
		m = (l+r)/2;
		if(seg[m].sum>=x)	r = m;
		else	l = m+1;
	}
	return l;
}
int main(){
	long long n,m;scanf("%lld%lld",&n,&m);
	long long sum = 0;
	long long x;
	int ans = 1e9, cns;
	for(int i=1; i<=n; ++i){
		scanf("%lld",&x);
		if(x==m&&ans==1e9)	ans=cns=i;
		sum+=x;
		seg[i].id = i;
		seg[i].sum = sum;
		if(sum==m)	ans=1,cns=i;
	}
	sort(seg+1, seg+n+1);
//	for(int i=1; i<=n; ++i)
//		dp[i] = seg[i].sum;
	for(int i=1; i<=n; ++i){
		//printf("%d \n", seg[i].id);
		int id;
		//id = lower_bound(dp+1, dp+1+n, seg[i].sum-m)-dp;
		id = find(seg[i].sum-m, n);
		if(id!=-1&&seg[i].id>seg[id].id){
			int c = id;
			while(seg[c].sum==seg[i].sum-m&&seg[i].id>seg[id].id){
				if(ans>seg[id].id+1)	ans=seg[id].id+1,cns=seg[i].id;
				else if(ans==seg[id].id+1)	cns=min(cns, seg[i].id);
				c++;
			}
		}
		//id = lower_bound(dp+1, dp+1+n, seg[i].sum+m)-dp;
		id = find(seg[i].sum-m, n);
		if(id!=-1&&seg[id].id>seg[i].id){
			int c = id;
			while(seg[c].sum==seg[i].sum+m&&seg[id].id>seg[i].id){
				if(ans>seg[i].id+1)	ans=seg[i].id+1,cns=seg[id].id;
				else if(ans==seg[i].id+1)	cns = min(cns, seg[id].id);
				c++;
			}
		}	
		//printf("%d %d\n", ans, cns);
	}
	if(ans!=1e9)	printf("%d %d\n", ans, cns);
	else	printf("No Solution\n");
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值