题目链接:点击打开题目
其实这是我们学校的校赛题,当时比赛没想通哦,隔了这么久才会做,膜拜宇神。今年校赛出题好头疼啊!
题解:首先就想到了二分。
我们先计算出来前缀和(下标从1开始)。
从a[1]开始,先求起始的数为a[1],满足条件的个数,这个很简单,把sum[L]到sum[n]放入vector中,然后排序,然后二分查找。
然后要计算从a[2]开始的满足条件的数的个数了(这段是关键)。那么我们首先要先从vector中把sum[L]删去(想一想为什么),然后看情况,我们要把vector中剩的数都减去a[1],然后再二分查找第一个大于等于L的数。但是再想想,既然都减去了a[1],那我们把L+a[1]不是更方便了。
按照上面一段的思路往后推就行了。想通了可以看一下代码。
代码如下:
#include<queue>
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define INF 0x3f3f3f3f
#define CLR(a,b) memset(a,b,sizeof(a))
#define PI acos(-1.0)
#define MAXSIZE 10000
int main()
{
int num[MAXSIZE+5];
int sum[MAXSIZE+5];
vector<int> arr;
int T;
int n,L,M,ans;
scanf ("%d",&T);
while (T--)
{
arr.clear();
sum[0] = 0;
scanf ("%d %d %d",&n,&L,&M);
for (int i = 1 ; i <= n ; i++)
{
scanf ("%d",&num[i]);
sum[i] = sum[i-1] + num[i];
}
for (int i = L ; i <= n ; i++)
arr.push_back(sum[i]);
sort(arr.begin(),arr.end());
//先单独计算从第一个数开始满足条件的个数
ans = arr.size() - (lower_bound(arr.begin(),arr.end(),M) - arr.begin());
//再依次向后推移
for (int i = L ; i <= n ; i++)
{
M += num[i-L+1];
arr.erase(lower_bound(arr.begin(),arr.end(),sum[i])); //删掉该sum
ans += arr.size() - (lower_bound(arr.begin(),arr.end(),M) - arr.begin()); //再次计算
}
cout << ans << endl;
}
return 0;
}