题解

原题请见题目链接

暴力求解

这是我们线下水题赛的第一题。这里为初学者提供一个思路,假设我们现在刚入 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); 
}

之后你就会看到如下的情况
solution1
好消息!没有爆零!
这时候我们就要考虑正解怎么做了。

前缀数组的做法

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

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

这里我们求出里面违反规则的 \(length\)

\[ans = R-l+1-length \]

这里附上 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] 保存的是违反规则的数的个数
posted @ 2023-06-04 21:56  mhunice  阅读(16)  评论(1)    收藏  举报