代码:《挑战程序设计竞赛》3.2.1
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 100000
int n, S; //n为数字个数, S为最小序列和
int num[MAX_N], sum[MAX_N + 1]; //记录数字 和 累加和
//方法一
void solve1()
{
fill(sum, sum + MAX_N + 1, 0);
for (int i = 0; i < n; i++)
{
sum[i + 1] = sum[i] + num[i]; //求数列累加和
}
if (sum[n] < S) //如果所有数的和小于要求的和,无解
{
cout << "0" << endl;
return;
}
int res = n;
//s记录子序列起点位置,t记录终点位置,
//通过枚举起点s,找到每个起点s对应的终点位置t,使得子序列num[s]到num[t-1]的和>=S,不断更新找到t-s的最小值,即为满足条件的最短序列长度
for (int s = 0; sum[s] + S <= sum[n]; s++) //当sum[s] + S > sum[n]终止循环,因为从当前起点一直加到最后一个数也无法满足>=S
{
int t = lower_bound(sum + s, sum + n, sum[s] + S) - sum;
res = min(res, t - s);
}
cout << res << endl;
}
//方法二
void solve2()
{
//初始化
int res = n + 1;
int s = 0, t = 0, sum = 0; //s为起点, t为终点
//如果num[s]到num[t]的总和大于S,则要使num[s+1]到num[t1]的值大于S,就需要t1>=t,因此不断从序列中拿出num[s],并在末尾不断插入新的num,直至总和无法满足>=S
for (;;)
{
while (t < n && sum < S)
{
sum += num[t++]; //只要有sum < S,就不断将sum增加num[t],并将终点t后移一位
}
if (sum < S) break; //如果从当前起点开始所有数字都加进去了和却小于S,终止
res = min(res, t - s);
sum -= num[s++]; //sum中减去num[s](第s+1个数),起点s往后移动一位
}
if (res > n) //无解
{
cout << "0" << endl;
return;
}
cout << res << endl;
}
int main()
{
cin >> n >> S;
for (int i = 0; i < n; i++)
{
cin >> num[i];
}
//solve1();
solve2();
return 0;
}
//测试用例
/*
5
11
1 2 3 4 5
*/