牛客题解 | 连续子区间和
题目
题解:
考察点: 滑动窗口,数形结合
易错点:
在本题中数据范围为\(10^6\),如果使用暴力求解是行不通的,因为如果使用复杂度为\(O(n^2)\)的暴力,那运算次数将达到\(10^{12}\),一般来说,在\(1s\)时间范围内\(OJ\)所能抗住的运算次数在\(10^8-10^9\)
解法:滑动窗口
首先,先从下图来观察出一个很重要的结论:
对于一个全由正整数构成的序列来说,如果区间\(L1\)中所有元素的和大于等于\(X\),则区间\(L1+L2\)中所有元素的和一定大于等于\(X\)。这是一个非常显然的结论,但在这里却非常有用。假设位置\(i\)为区间\(L1\)和\(L2\)的分隔线,\(L1\)中所有元素的和大于等于\(X\),则当前位置\(i\)对答案的贡献为\(n-i+1\),因为后面无论加上多少个元素,总可以,满足区间的和大于等于\(X\)。
有了上述结论,可以很自然使用滑动窗口算法来做这个问题。对于当前位置\(i\),指针\(j\)指向其所对应区间\(L1\)的开头。如果\(XL1\)大于\(X\),则指针\(j\)从\(L1\)的开始位置往后移动,直到\(L1\)所对应的区间小于\(X\)为止。同时指针每移动一次,\(i\)对答案的贡献增加\(n-i+1\),因为其后的都满足大于等于\(X\)。整个过程中最多\(i\)遍历1次,\(j\)遍历一次,所以复杂度为\(O(2n)\),也就是\(O(n)\)级别的复杂度
#include "bits/stdc++.h"
using namespace std;
const int maxn=1e6+100;
typedef long long LL;
int n,a[maxn];
LL x;
int main()
{
scanf("%d%lld",&n,&x);
LL sum=0,ans=0;
int j=1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
if(sum>=x){
ans+=n-i+1;
while(j<=i&&sum>=x){
sum-=a[j];
j++;
if(sum>=x) ans+=n-i+1;
else break;
}
}
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号