我真傻,真的
way1:two points
当输入为1的时候要特判
这个我知道,
但鬼能想到我输出了那个数,,,,
okk,其实可以直接下标从1开始
本来还想过用一次遍历,然后搞一个数组存之前那个maxn,,
判断条件太复杂了,放弃了:-(
#include<iostream>
#include<vector>
#include <queue>
#include <algorithm>
#include<cstdio>
#include <map>
using namespace std;
int main(){
int n,m;
scanf("%d %d",&n,&m);
int num[100010];
for (int i = 0; i < n; ++i) {
scanf("%d",&num[i]);
}
int count=0;
int j=0;//left
if(n==1){
cout<<"1-1"<<endl;
}
else {
int maxn = 0x3f3f3f3f;//这是所有数中,大于等于m中的最小的
for (int i = 0; i < n; ++i) {
count += num[i];
while (i < n && count >= m) {//限制>=m
maxn = min(maxn, count);
count -= num[j];
j++;
}
}
int q = 0;
count = 0;
for (int i = 0; i < n; ++i) {
count += num[i];
while (i < n && count >= m) {//限制>=m
if (count == maxn) {
cout << q + 1 << "-" << i + 1 << endl;
}
count -= num[q];
q++;
}
}
}
}
way2 前缀和+二分
车祸现场:
舒服了:
不得不说,二分的边界问题太难处理了,有什么问题肯定首想第一个问题
#include<iostream>
#include<vector>
#include <queue>
#include <algorithm>
#include<cstdio>
#include <map>
using namespace std;
//二分+前缀和
int num[100010];
int sum[100020];
int upper_bound(int l ,int r,int x){//返回 (l,r)内第一个大于 x的值
int right = r;
int left = l;
int mid;
while(left<right){
mid=(left+right)/2;
if(sum[mid]>x){//这里是大于,也就是说如果mid刚好等于x的话是会往上移动的
right=mid;//注意这里不是mid-1
}
else{
left=mid+1;
}
}
return left;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
int maxn = 0x3f3f3f3f;
for (int i = 1; i <= n; ++i) {//下标从一开始不需要特判
scanf("%d", &num[i]);
sum[i] += sum[i - 1] + num[i];
}
for (int i = 1; i <= n; ++i) {
int j = upper_bound(i, n + 1, sum[i - 1] + m);
if (sum[j - 1] - sum[i - 1] == m) {//返回的是>,所以你要搞j-1
maxn = m;
break;
} else if (j <= n && sum[j] - sum[i - 1] < maxn) {
maxn = sum[j] - sum[i - 1];
}
}
for (int i = 1; i <= n; ++i) {
int j = upper_bound(i, n + 1, sum[i - 1] + maxn);
if(sum[j-1]-sum[i-1]==maxn){
cout<<i<<"-"<<j-1<<endl;
}
}
}