这题主要是有负数,如果没有负数的话我觉得到可以用尺取法做一做、
我这题的思路做一个前缀和并记录那个前缀的末位置,排序前缀和,类似暴力枚举的思路 判断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");
}