题意:求一串的数字中连续的一段,使得这个连续的段内数字的和恰好等于所期望的值m。如果不能找到恰好等于,就找让自己付出最少的价格(总和必须大于等于所给值)的那段区间。求所有可能的结果。
分析:简单模拟有两个超时。后来想到因为sum数组是递增的,所以改用二分法查找~子函数的作用是二分查找,修改tempans和j的值~一开始接收输入的时候可以直接保存它的sum函数,即sum[i]表示1~i的所有数字的总和~
Sample Input 1:
16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13
Sample Output 1:
1-5
4-6
7-8
11-11
Sample Input 2:
5 13
2 4 5 7 9
Sample Output 2:
2-4 4-5
#include<bits/stdc++.h>
using namespace std;
int sum[100005];
vector<int> tmp,ans;
int n,m;
void BinarySearch(int i,int &j,int &tmpans) {
int left=i,right=n,mid; //左闭右开
while(left<right) {
mid=(left+right)>>1;
if(sum[mid]-sum[i-1]>=m) right=mid;
else left=mid+1;
}
j=right;
tmpans=sum[j]-sum[i-1]; //i到j的部分和
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) { //部分和
scanf("%d",&sum[i]);
sum[i]+=sum[i-1];
}
int minans=sum[n];
for(int i=1; i<=n; i++) {
int j,tmpans;
BinarySearch(i,j,tmpans); //j和tmpans使用引用
if(tmpans>minans) continue; //直接continue:大于minans
else if(tmpans>=m) { //否则如果>=m
if(tmpans<minans) { //若小于则清空向量,更新minans
ans.clear();
minans=tmpans;
ans.push_back(i);
ans.push_back(j);
}
else if(tmpans==minans){ //当前最优解的另一种方案
ans.push_back(i);
ans.push_back(j);
}
}
}
for(int i=0; i<ans.size(); i+=2)
cout<<ans[i]<<"-"<<ans[i+1]<<endl;
return 0;
}