题目:
问题描述
给你一个长度为 𝑛n 的数组 𝑎a 和一个数字 𝑚m ,请你计算这个数组有多少个连续子序列的和大于等于 𝑚m ?
如果两个连续子序列来自数组中的不同位置,我们认为它们是不同的,即使它们在内容上是相同的。
输入格式
第一行输入两个整数表示 𝑛n 和 𝑚m 。
第二行输出 𝑛n 个整数表示 𝑎a 数组的元素。
输出格式
输出一个整数表示 𝑎a 数组有多少个连续子序列的和大于等于 𝑚m 。
样例输入
4 10
6 1 2 7
样例输出
2
说明
保证对于所有数据有:1≤𝑛≤105,1≤𝑚≤1010,1≤𝑎[𝑖]≤1051≤n≤105,1≤m≤1010,1≤a[i]≤105 。
代码:
#include <iostream>
using namespace std;
long long m;
const int N=1000010;
int a[N];
int main()
{
// 请在此输入您的代码
//窗口滑动,[slow,fast]这个区间的和sum,当满足sum>m时说明快指针从slow到fast+fast之后到n的所有子数组也符合,
//则此时count=count+n-fast即为slow开始这个位置的连续子序列的个数
//1,2,3,4,5,6 [slow,fast]=[0-3]=1,2,3,4,sum=10>9 则1,2,3,4,5 1,2,3,4,5,6都符合,所以count=count+6-3
//因为是连续,所以1,2,3,4,6不可以。所以直接加n-fast5,6即可
//当这个慢指针开始的都满足完了,窗口在王后移动一个,同时sum减去这个时刻slow所指向的值,slow++慢指针往后移动,fast也往后移动,并在继续求和,当满足sum>m时的值
//最后输出count即为最终结果
int n;
long long sum=0,count=0;
//注意sum最后是long long型的保险,因为最大sum=100000*100000=1e10超出了整型int的范围
//count不知道为什么int类型的不行有一个测试样例没通过。最坏的情况第一个数字就>m。则count会有(1+2+3+...+n)=(n*(n+1))/2会有1e10大于int范围了
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a[i];
}
int slow=0,fast=0;
for(;fast<n;fast++){
sum+=a[fast];//窗口滑动向后求和
while((sum>=m)&&slow<=fast){
count+=(n-fast);//注意加括号,不然就算成了count=count+n了
sum-=a[slow];//窗口滑动
slow++;//指针后移
//for循环后fast自动加一后移
}
}
cout<<count<<endl;
return 0;
}
注意:
注意count和sum的取值范围可能会为long long 型
快慢双指针,窗口滑动
count=count+(n-fast)//如果[slow,fast]的和满足,则从fast开始后的都会满足