题意:在某一序列中,问有多少个好区间------区间长度大于等于 K 并且第 K 大的数大于等于 T。
解题思路:
1、满足第 K 大的数大于等于 T,相当于在该区间中至少有 K 个数大于等于 T------用后缀数组存储该序列中前 i 个位置大于 T 的数。
2、如果固定左端点,那么对于一个好区间,那么右端点一定是可以往后延续的,若左端点向右移动,那么离它最近的右端点不可能向左移动。因此可以使用双指针来做这题。
3、如果固定右端点,那么对于一个好区间,肯定是某个左端点往左都满足题意,双指针就ok了!
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
const int maxn = 1e7+5;
int s[maxn];
int main()
{
ios::sync_with_stdio(false);
long long a,n,k,T,b,c,p;
cin>>n>>k>>T>>a>>b>>c>>p;
s[0] = 0;
for(int i = 1; i <= n; i++)
{
a = (a * b + c) % p;
s[i] = s[i-1];
if(a >= T) s[i]++;//前缀和--从 1-i 区间中大于 T 的个数
}
long long ans = 0,l = 1,r = 1;
// while(true)
// {
// while(s[r] - s[l-1] < k) r++;
// if(r > n) break;
// ans += n - r + 1;
// l++;
// }
while(l <= n)
{
// r = k + l - 1;//从 l 开始的区间直接跳到到长度为 k,l 在往前移动,不需要重置 r,否则会超时。
while(r <= n)
{
if(s[r] - s[l-1] >= k)//这段区间中大于 T 的数的个数至少为 K
{
ans += n - r + 1; // 满足条件之后,再加上任意一个都是满足的区间
break;
}
r++;
}
if(r > n) break;//当 r>n 时,后面的就一定没有满足条件的区间
l++;
}
printf("%lld\n",ans);
return 0;
}