题目描述
给出一个长度为n的数组和一个整数k。
对于数字中连续的某一段,我们称之为子段。
请找到数组中有多少个连续的非空子段,使得这段数字的和大于等于k。
输入格式
第一行两个整数nn和kk。
第二行nn个整数aiai
1≤n≤1051≤n≤105
1≤ai≤1051≤ai≤105
1≤k≤10101≤k≤1010
输出格式
输出一个整数
样例输入
4 10
6 1 2 7
样例输出
2
提示
对于样例的解释:
从第1个数,到第4个数的和为16
从第2个数,到第4个数的和为10
16和10都大于等于10,因此答案为2
法一:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxx = 1000050;
ll n, m, k, t, now, p, ans;
const double pi = acos(-1.0);
ll a[1000050], w[1000050];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
ll sum = 0;
for (int i = 0; i < n; i++)//存入数组
{
cin >> a[i];
}
int j = 0;
for (int i = 0; i < n; i++)//依次开始遍历
{
sum += a[i];//sum这里代表的是所遍历到的数的和
while (sum >= k && j <= i)//子段的遍历
{
sum -= a[j];//挨个进行删除观察是否符合
ans += n - i;//用n - i 替代了一个数组的作用
j++;//子段记录+1
}
}
cout << ans << endl;
return 0;
}
法二:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxx = 1000050;
ll n, m, k, t, now, p , ans;
const double pi = acos(-1.0);
ll fa[1000050], w[1000050];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
int a;
cin >> a;
fa[i] = fa[i - 1] + a;//前缀和
}
for (int i = 1; i <= n; i++)
{
if (fa[i] < m)//当其前缀和都小于m时直接跳过
{
continue;
}
ans++;//否则就记录一次
w[i] = w[i - 1];//为上一次记录的个数(至少有这么多)
for (int j = w[i] + 1; j < i; j++)//之所以+1是因为不+1的那部分子段已经在上一轮被计算过了
{
if (fa[i] - fa[j] >= m)//进行子段的查找(呈收缩状
{
w[i] ++;
}
else//如果不满足的就退出
{
break;
}
}
ans += w[i];//加上子段的个数
}
cout << ans << endl;
return 0;
}
个人感觉法一法二无实质区别,均是采用前缀和的思想进行时间和空间的节省