CF1817A Almost Increasing Subsequence

题目大意

给你一些数,定义不能有连续三个数使得后两个数小于等于前一个数。求一段区间内最大符合条件的子序列有多长。

题意分析

其实我们不难发现,这道题如此巨大的数据范围,时间复杂度肯定是 \(O(n)\) 的。这就容易想到了前缀和。我们需要预处理出当前位置比前一个位置大的连续区间的长度,接着求出大于二的长度的前缀和。因为存的时候漏了个一。之后你想使其符合条件,就需要将除了两个之外的所有字符都删掉。具体可参考代码理解。

CODE

#include<bits/stdc++.h>
#define wk(x) write(x),putchar(' ')
#define wh(x) write(x),putchar('\n')
#define ll long long
#define ull unsigned long long
#define ri register int
#define INF 2147483647
#define mod 998244353
#define N 250005
#define NO printf("No\n")
#define YES printf("Yes\n")

using namespace std;

int n, m, k, jk, ans, sum, num, cnt, tot;
int head[N], dis[N], vis[N], wis[N], f[N];

// 读取函数
void read(int &x)
{
	x = 0;
	int ff = 1;
	char ty;
	ty = getchar();
	while(!(ty >= '0' && ty <= '9'))
	{
		if(ty == '-') ff = -1;
		ty = getchar();
	}
	while(ty >= '0' && ty <= '9')
		x = (x << 3) + (x << 1) + ty - '0', ty = getchar();
	x *= ff;
	return;
}

// 写入函数
void write(int x){
	if(x == 0){
		putchar('0');
		return;
	}
	if(x < 0){
		x = -x;
		putchar('-');
	}
	char asd[201];
	int ip = 0;
	while(x) asd[++ip] = x % 10 + '0', x /= 10;
	for(int i = ip; i >= 1; i--) putchar(asd[i]);
	return;
}

signed main()
{
	// 读取序列长度n和查询次数m
	read(n), read(m);

	// 读取序列的元素并计算vis和f数组
	for(int i = 1; i <= n; i++){
		read(dis[i]);
		if(i != 1 && dis[i - 1] >= dis[i]) vis[i] = vis[i - 1] + 1;  // 记录递减区间的长度
		else vis[i] = 0;  // 否则为0
		f[i] = f[i - 1] + (vis[i] >= 2);  // 更新f数组,记录递减子序列的长度
	}

	// 处理每个查询
	int x, y;
	while(m--){
		read(x), read(y);
		wh(y - x + 1 - (f[y] - f[min(x + 1, y)]));  // 由于要大于二的才算,所以要让其位置加一的值与右区间取最小值。
	}

	return 0;
}
posted @ 2025-11-22 16:21  Red_river_hzh  阅读(4)  评论(0)    收藏  举报