题解

发布时间 2023-06-04 22:01:59作者: mhunice

原题请见题目链接

1. 暴力求解

这是我们线下水题赛的T1 这里为初学者提供一个思路,假设我们现在刚入OI,在考场上如何怎么优雅的避免保灵

显然 我们只要用一个 \(O(n)\) 的暴力去扫描就行了,但是直接向后扫 \(i+1,i+2\) 这样走很容易寄。因为你在\(i+1\) 跳的时候很容易把后面跳过了 ,导致你的最长序列会至少-2(我看别的题解都没有说明 应该是太简单了吧 )

那这样我们就可以初步得出这个暴力来对拍了。

我们只需定义一个 \(flag\) 来暂时保存你现在的长度 只要你扫描到 \(i-1,i-2\) 都比这个 \(i\) 大 ,即为不合法。我们在清零之前我们和 \(ans\) 取一个 \(max\) 即可

#define _for(i,a,b) for(int (i) = (a); i <= (b); i++) 
using namespace std; 
int a[200006]; 
int n, q; 
int main( ) { 

scanf("%d%d",&n,&q);
_for(i,1,n) scanf("%d",&a[i]); 
while(q--) 
{ 
	int l,r; 
	int maxn = 0,flag = 0; 
	scanf("%d%d",&l,&r); 
	_for(i,l,r) 
		{ flag ++; 
			if(a[i] <= a[i - 1] && a[i - 1 ] <= a[i - 2] && i >= 3)
			{ flag--; } 
			maxn = max(maxn,flag); 
		} 
			printf("%d\n",maxn); 
	} 
//fclose(stdin);fclose(stdout); 
}

之后你就会看到如下的情况

好消息! 没有爆零!
这时候我们就要考虑正解怎么做了

2. 前缀数组的做法

Q:为什么我们这道题可以用前缀数组去做呢 为什么想到这里呢?

ans:因为这个玩意是可以共享给后面的。假设你 \(l\)\(l + r\) 中间没有任何一个违反规则的三元组,那么你可以很快的求出 \([l,l+2]\) 的长度就为 \([l,l+r] - [l+3,l+r]\) 所以我们可以用前缀的思想求解。

这里我们求出里面违反规则的 \(length\)\(R-l+1-ans\) 即可

这里附上ac代码

#define _for(i,a,b) for(int (i) = (a); i <= (b); i++)
using namespace std;

int a[200006],c[2000006],b,cnt;
int n, q;

int main( )
{
//	freopen("a.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	scanf("%d%d",&n,&q);
	bool flag  = 1;
	int b;
	_for(i,1,n) {
		
		scanf("%d",&c[i]);
		if(i >= 3)
		{
			b = 0;
			if(c[i] <= c[i - 1] && c[i - 1] <= c[i - 2]) 
			b = 1;
			a[i] += a[i -1] + b;
		}
	}
	
	while(q--)
	{
		int l,r;
		int maxn;
		scanf("%d%d",&l,&r);
		maxn = a[r] - a[l+1];
		if(r-l+1 <= 2)  maxn = r-l+1;
		else maxn = r-l+1-maxn;
		printf("%d\n",maxn);
	}
	fclose(stdin);fclose(stdout);

c[i] 为原始序列 ,a[i] 保存的是违反规则的数的个数