1. 程式人生 > >51Nod - 1495-中國好區間-尺取法

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;
}