题解
原题请见题目链接
暴力求解
这是我们线下水题赛的第一题。这里为初学者提供一个思路,假设我们现在刚入 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);
}
之后你就会看到如下的情况

好消息!没有爆零!
这时候我们就要考虑正解怎么做了。
前缀数组的做法
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] 保存的是违反规则的数的个数

浙公网安备 33010602011771号