51Nod - 1495-中国好区间-尺取法

题意:在某一序列中,问有多少个好区间------区间长度大于等于 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;
}

猜你喜欢

转载自blog.csdn.net/cutedumpling/article/details/82918934