CF1817A Almost Increasing Subsequence 题解

题面

2023.5.18 修正关于前缀和数组的说法,与代码适配的思路。

题意

给定长度为 n 一个序列 a 以及 q 次询问,每次询问给出 lr,要求找出序列 a[l,r] 内最长的几乎递增子序列。

对于几乎递增的定义:如果一个序列中不存在连续的三个数 xyz,使得 xy z,则这个序列是几乎递增的。

思路

用一个前缀和数组 s 记录,其中 si 表示从 a3ai 中满足 ai2ai1aii 的数量。对于每次询问,输出 rl+1(srsl+1) 即可。

简单做个解释,对于每个 ai2ai1ai,只有 ai 会决定是否满足当前式子,所以不选择 ai。举个例子:

5 4 3 2 1 2 3 4 5 1

在上面的序列中,子序列 5,4,34,3,23,2,1 都是不满足题目要求的,当输入 l=1r=10 时,输出答案为 7。可以想到,选中的 7 个数可以是这样的:

5 43 2 12 3 4 5 1

也可以是这样的:

5 4 32 1 2 3 4 5 1

为了区分选择与未被选择,这里用斜体与粗体区分开,选择方法不止两种,上面的第一种选法,与给出的解释一致。

证明

当序列中存在 aiaj2aj1ajji+13 时,对于这一部分,一定有 ji1 个连续的三个数 xyz,使得 xy z

从第 j 项开始,每不选择一个 aj,相对应序列 aj2,aj1,aj 的规律就会被破坏,要破坏掉整个从 aiaj 的序列的规律,至少要破坏到 ai+2 的位置(也包括 ai+2 这个位置)。故最多只能选择 2 个数。

ji+1=3,即最短满足 xy z 的序列时,最多只能选择 2 个,也就是至少要不选一个。(这里其实不选哪一个都是一样的)

前缀数组(2023.5.18 新增)

对于每一个 si,记录的是从 a3ai 中满足 ai2ai1aii 的数量。而对于区间 [l,r] 来说,第 al 项对应的序列(上面说的三元组)从 al2 就开始了,第 al+1 项对应的序列从 al1 就开始了,因此不能将第 al 与第 al+1 项对应的序列算入这个区间内。所以最后的答案应该是从第 sl+2 项算起,结论就是 rl+1(srs(l+2)1),即 rl+1(srsl+1)

代码

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#define ll long long
#define inf 0x3f3f3f3f
#define fr(i , a , b) for(ll i = a ; i <= b ; ++i)
#define fo(i , a , b) for(ll i = a ; i >= b ; --i)
#pragma comment(linker , "/stack : 200000000")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
using namespace std;
inline char gchar()
{
    static char buf[1000000] , *p1 = buf , *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 1000000 , stdin) , p1 == p2) ? EOF : *p1++;
}
inline ll read()
{
    ll x = 0 , f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
	  {
        if(ch == '-')
        {
        	f = -1;
		}
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
	  {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
ll n , q , a[200005];
ll l , r;
ll f[200005] , now;
inline ll answer(ll L , ll R)
{
    ll ans = f[R] - f[L + 1];
    if(R - L + 1 <= 2)//特判,区间长度为2或1
    {
        ans = 0;
    }
    return R - L + 1 - ans;
}
signed main()
{
    n = read();
    q = read();
    fr(i , 1 , n)
    {
        a[i] = read();
        if(i >= 3)
        {
            now = 0;
            if(a[i - 2] >= a[i - 1] && a[i - 1] >= a[i])
            {
                now = 1;
            }
            f[i] = f[i - 1] + now;
        }
    }
    while(q--)
    {
        l = read();
        r = read();
        printf("%lld\n" , answer(l , r));
    }
    system("pause");
    return 0;
}
posted @   心海秋的墨木仄  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示