题目大意
给你一串数字和一个上限
求这串数字中>=上限的最短子序列
intput
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
output
2
3
这道题有一个坑点就是如果找不到
输出0
第一种方法
把每一段的权值求出来
先找到从第几个点开始之后的点都能大于上限
接着从这一段中依次删去前面的段
直到不大于上限
#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int num[N], sum[N];
int main(){
int n, s;
while (scanf("%d%d", &n, &s) != EOF) {
for (int i = 1; i <= n; i++)
scanf("%d", &num[i]);
sum[0] = 0;
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + num[i];
int ans = n + 1, c = 1;
for (int i = 1; i <= n; i++) {
if (sum[c - 1] > sum[i] - s)
continue;
while (sum[c] <= sum[i] - s)
c++;
ans = min(ans, i - c + 1);
}
printf("%d\n", ans == n + 1 ? 0 : ans);
}
return 0;
}
方法二
一样也是先找到
从第几个点开始之后的段落权值能大于上限
接着是找要删掉前面的几个点
这边开始二分查找
#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int sum[N];
int n , s;
int erfen(int x){
if (sum[x] < s)
return 0;
int left = 1, right = x;
while (left < right) {
int mid = (left + right) / 2;
if (sum[x] - sum[mid] >= s)
left = mid + 1;
else
right = mid;
}
return left;
}
int main(){
while (scanf("%d%d", &n, &s) != EOF) {
sum[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &sum[i]);
sum[i] += sum[i - 1];
}
if (sum[n] < s) {
printf("0\n");
continue;
}
int ans = n + 1;
for (int i = 1; i <= n; i++) {
int k = erfen(i);
if (k)
ans = min(ans, i - k + 1);
}
printf("%d\n", ans);
}
return 0;
}