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;
}
本文来自博客园,作者:Red_river_hzh,转载请注明原文链接:https://www.cnblogs.com/Red-river-hzh/p/19257069

浙公网安备 33010602011771号