题意
求长度为n的序列的一个长度最小而其和不小于S的子序列。
题解
先计算每个位置前缀和,枚举子序列的起点,二分搜索使序列和不小于S的末尾位置。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
ll sum[maxn], a[maxn];
int n, s, t;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
for(cin >> t; t--; )
{
cin >> n >> s;
memset(sum, 0, sizeof(sum));
for(int i = 0; i < n; ++i)
{
cin >> a[i];
sum[i + 1] = sum[i] + a[i];
}
if(sum[n] < s){
cout << 0 << endl;
continue;
}
int res = n;
for(int i = 0; sum[i] + s < sum[n]; ++i){
int pos = lower_bound(sum + i, sum + n, sum[i] + s) - sum;
res = min(res, pos - i);
}
cout << res << endl;
}
return 0;
}
尺取法
反复推进区间的开头和结尾,来求取满足条件的最小区间。
void solve()
{
int sum = 0, res = n + 1;
int s = 0, t = 0;
for(; ; ){
while(t < n && sum < S) sum += a[t++];
if(sum < S) break;
res = min(res, t - s);
sum -= a[s++];
}
if(res > n) res = 0;
cout << res << endl;
}