首页 > 其他分享 >CF145E Lucky Queries 题解

CF145E Lucky Queries 题解

时间:2024-01-25 23:15:08浏览次数:25  
标签:curr int 题解 Lucky template LIS include CF145E define

题目链接:CF 或者 洛谷

前置知识点:序列操作

本文关键词 约定俗称:因为频繁敲最长不下降子序列 \(LNCS\) 和最长不上升子序列 \(LNIS\) 太麻烦了,下文将 \(000011111\) 这种最长不降子序列用 \(LIS\) 描述,\(1111100000\) 这种最长不升子序列用 \(LDS\) 描述。

这里面只有 \(4\) 和 \(7\),抽象当做 \(0\) 和 \(1\),那么那个交换两种数操作其实就是区间取反操作,接下来解决如何维护区间的 \(01序列LIS\) 问题。\(01\) 序列比较特别,它的 \(LIS\) 一定是类似于 \(00001111\) 这样的形式,其中 \(0\) 与 \(1\) 的个数都可以为 \(0\)。如果做过维护最大子段和问题的很容易想到这类问题,其实也可以由局部的最大子段和进行拼段得到新的区间上的最大子段和。

难点讲解

如何在线段树上的 pushUp 中去进行计算 \(LIS\)。

如图所示,具体数字数值不做参考,如果我们已经知道了两个节点区间表示的 \(LIS\),容易知道如果是左边的 \(LIS\),那么一定要加上右边的 \(1\) 的个数才能拼成新的 \(LIS\),右边的 \(LIS\) 一定需要加上左边的 \(0\) 的个数才能组成父节点的 \(LIS\)。那么考虑二者中最大的一定是父节点的 \(LIS\) 吗?

证明:

先考虑一个特殊情况是否也满足,假如它的 \(LIS\) 为全 \(1\) 或者全 \(0\)。容易发现,如果左边节点为全 \(0\),那么在右边的 \(LIS\) 拼左边的 \(0\) 的个数的时候,就能涵盖了这种情况。

全 \(1\) 也是同理的。那么也就是说这类的特殊情况是被包括在我们讨论的 \(0000011111\) 这种连续段中的,并不会影响,即 \(0\) 或者 \(1\) 的个数为 \(0\) 并不影响讨论。

考虑全局 \(LIS\) 的特点,对于父节点的 \(LIS\) 一定也是长 \(0000011111\) 这样子的,并且一定有一个分割点 \(mid\) 使得这个 \(01\) 串分割为两部分,左半边为左区间的子序列,右半边为右区间的子序列,当然,这个子序列长度也可恶意为 \(0\),比如:

\([1,5]\) 区间,它的串表示为 \(11100\),其中 \([1,3]\) 的串为 \(111\),\([4,5]\) 的串为 \(00\),而 \([1,5]\) 的 \(LIS\) 为 \(111\),显然我们这个 \(mid\) 该放在最后一个 \(1\) 的后面,前面的 \(111\) 为左半区间,后面的 “空串” 为右半区间的子序列。

那么我们来考虑 \(mid\) 除开特殊的空串情况以外的可能情况,其实空串也被包括在了上述说的全 \(1\) 或者 全 \(0\) 的特殊情况中了。

  1. \(mid\) 放在了某个 \(0\) 上,那么将原串分割为 \(000\) 与 \(000011111\),前者为左区间的串,显然最优为 \(LIS\) 时,应该取 \(0\) 的数量,后面要求 \(01\) 串这种连续串最长,显而易见是右区间的 \(LIS\)。符合我们说的其中一个情况:\(Zero_{left}+LIS_{right}\)。

  2. \(mid\) 放在某个 \(1\) 上,那么同上分析分割为了 \(0001111\) 与 \(11111\),显然最优的 \(LIS\) 时为:\(LIS_{left}+One_{right}\)。

综上所述,\(LIS\) 的所有情况是被上述两种情况给包含了的,我们并没有遗漏情况。

0-1串 LIS 带翻转操作

现在这玩意带上翻转操作咋整,看到前置知识点那题没,其实 \(0-1 串\) 是一个非常好的问题结构,它的取反会得到一个对偶问题:\(LDS\) 最长不增序列,即 \(111111000000\),类似于前置知识点问题,我们同时类似维护它的对偶问题的的答案,翻转即是两个问题的答案互换即可。读者可以先写写前置知识点的那题,可以先学习我的那篇题解再进行本题观摩就很容易懂了对偶问题的答案互换的意思了。

参照代码
#include <bits/stdc++.h>

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")

// #define isPbdsFile

#ifdef isPbdsFile

#include <bits/extc++.h>

#else

#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope>

#endif

using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};

template <typename T>
int disc(T* a, int n)
{
    return unique(a + 1, a + n + 1) - (a + 1);
}

template <typename T>
T lowBit(T x)
{
    return x & -x;
}

template <typename T>
T Rand(T l, T r)
{
    static mt19937 Rand(time(nullptr));
    uniform_int_distribution<T> dis(l, r);
    return dis(Rand);
}

template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
    return (a % b + b) % b;
}

template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
    a %= c;
    T1 ans = 1;
    for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
    return modt(ans, c);
}

template <typename T>
void read(T& x)
{
    x = 0;
    T sign = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-')sign = -1;
        ch = getchar();
    }
    while (isdigit(ch))
    {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    x *= sign;
}

template <typename T, typename... U>
void read(T& x, U&... y)
{
    read(x);
    read(y...);
}

template <typename T>
void write(T x)
{
    if (typeid(x) == typeid(char))return;
    if (x < 0)x = -x, putchar('-');
    if (x > 9)write(x / 10);
    putchar(x % 10 ^ 48);
}

template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
    write(x), putchar(c);
    write(c, y...);
}


template <typename T11, typename T22, typename T33>
struct T3
{
    T11 one;
    T22 tow;
    T33 three;

    bool operator<(const T3 other) const
    {
        if (one == other.one)
        {
            if (tow == other.tow)return three < other.three;
            return tow < other.tow;
        }
        return one < other.one;
    }

    T3() { one = tow = three = 0; }

    T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
    {
    }
};

template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
    if (x < y)x = y;
}

template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
    if (x > y)x = y;
}

constexpr int N = 1e6 + 10;

struct Node
{
    int sum4, sum7, LIS, LDS;
    int rev, len;
} node[N << 2];

#define sum4(x) node[x].sum4
#define sum7(x) node[x].sum7
#define LIS(x) node[x].LIS
#define LDS(x) node[x].LDS
#define len(x) node[x].len
#define rev(x) node[x].rev

inline void push_up(const int curr)
{
    sum4(curr) = sum4(ls(curr)) + sum4(rs(curr));
    sum7(curr) = sum7(ls(curr)) + sum7(rs(curr));
    LIS(curr) = max(LIS(ls(curr)) + sum7(rs(curr)),sum4(ls(curr)) + LIS(rs(curr)));
    LDS(curr) = max(LDS(ls(curr)) + sum4(rs(curr)),sum7(ls(curr)) + LDS(rs(curr)));
}

inline void RevTag(const int curr)
{
    sum4(curr) = len(curr) - sum4(curr);
    sum7(curr) = len(curr) - sum7(curr);
    swap(LIS(curr),LDS(curr));
    rev(curr) ^= 1;
}

inline void push_down(const int curr)
{
    if (rev(curr))
    {
        RevTag(ls(curr)), RevTag(rs(curr));
        rev(curr) = 0;
    }
}

int n, q;
char a[N];

inline void build(const int curr = 1, const int l = 1, const int r = n)
{
    len(curr) = r - l + 1;
    const int mid = l + r >> 1;
    if (l == r)
    {
        LIS(curr) = LDS(curr) = 1;
        sum4(curr) = a[l] == '4';
        sum7(curr) = a[l] == '7';
        return;
    }
    build(ls(curr), l, mid);
    build(rs(curr), mid + 1, r);
    push_up(curr);
}

inline void Rev(const int curr, const int l, const int r, const int s = 1, const int e = n)
{
    if (l <= s and e <= r)
    {
        RevTag(curr);
        return;
    }
    const int mid = s + e >> 1;
    push_down(curr);
    if (l <= mid)Rev(ls(curr), l, r, s, mid);
    if (r > mid)Rev(rs(curr), l, r, mid + 1, e);
    push_up(curr);
}

string s;

inline void solve()
{
    cin >> n >> q;
    forn(i, 1, n)cin >> a[i];
    build();
    while (q--)
    {
        cin >> s;
        if (s == "count")cout << LIS(1) << endl;
        else
        {
            int l, r;
            cin >> l >> r;
            Rev(1, l, r);
        }
    }
}

signed int main()
{
    // MyFile
    Spider
    //------------------------------------------------------
    // clock_t start = clock();
    int test = 1;
    //    read(test);
    // cin >> test;
    forn(i, 1, test)solve();
    //    while (cin >> n, n)solve();
    //    while (cin >> test)solve();
    // clock_t end = clock();
    // cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}

\[时间复杂度为:\ O(q\log{n}) \]

标签:curr,int,题解,Lucky,template,LIS,include,CF145E,define
From: https://www.cnblogs.com/Athanasy/p/17988383

相关文章

  • 魔法少女LJJ 题解
    魔法少女LJJ题解这题纯属就是迷惑题。。为什么这么说?注意数据范围:对100%的数据\(0\leqm\leq400000\),\(c\leq7\)。\(c\leq7\)!!这意味着根本没有删除操作。就连样例也是错的。Solution这题的各种操作,用并查集+线段树合并完成。如果你是被题目数据范围晃飞的,建议......
  • loj 6095 花神的嘲讽计划 题解
    题目哈希记录每个\(k\)长度的串,询问的时候可以拿主席树或二分,这里说下二分。将\(n-k+1\)个串从小到大排序,以哈希值为第一关键字,序号为第二关键字。每次询问直接查找大于等于当前哈希值的位置即可,找到之后判断一下合不合法即可。具体看代码:#include<bits/stdc++.h>typede......
  • P8659 [蓝桥杯 2017 国 A] 数组操作 题解
    题目链接:洛谷或者蓝桥杯或者C语言中文网几个OJ的AC记录:忘了哪个OJ的:洛谷:C语言中文网:蓝桥杯:emmmmmmm,好像每个OJ给的时限和空间还不一样,蓝桥杯官方还给了$3s$和$2G$,C语言中文网机子比较老可能,挺卡常的,开了个究极快读和指令集就过去了,也可以自己调下重构常数,偷懒......
  • P3355 骑士共存问题题解
    题目链接:P3355骑士共存问题-洛谷|计算机科学教育新生态(luogu.com.cn)题解:棋盘问题考虑黑白染色成为二分图后做。观察马的性质,可知一个点只能到一个异色点,所以,构造方案可以先将所有同色点放上马,再考虑有那些异色点不可以放置。方法一:网络流,时间复杂度为O(|E|min(|E|0.5......
  • P7900 [COCI2006-2007#2] SJECIŠTA_题解
    [COCI2006-2007#2]SJECIŠTA_题解rt我们来看一下题目描述考虑一个有$n$个顶点的凸多边形,且这个多边形没有任何三个(或以上)的对角线交于一点。这句话什么意思?当顶点为$n$的图形为正多边形时便有可能出现一个点是有三条线相交而构成的如图如图情况就有三个......
  • P9779_[HUSTFC 2023] 不定项选择题_题解
    rt题目有一道共n个选项的不定项选择题,它的答案至少包含一个选项,由于题目与选项的内容晦涩难懂,你打算通过尝试每一种可能的答案来通过这道题。初始时所有选项都没有被勾选,你可以执行任意次下述操作:勾选一个当前未被勾选的选项。取消勾选一个当前已被勾选的选项。当你......
  • P2045 方格取数加强版题解
    题目链接:P2045方格取数加强版-洛谷|计算机科学教育新生态(luogu.com.cn)题目:出一个n*n的矩阵,每一格有一个非负整数A{i,j}且A{i,j} <=10^3现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要......
  • CF349B Color the Fence 题解 贪心
    贪心题意:你一共有\(v\)元,给你数字\(1\)~\(9\)的价值,求出你能够买下的数字组成的最大数。思路首先,我们知道能够买下的数字个数越多,组成数字的位数就越多,结果自然就越大,那么,根据贪心策略,我们可以先全买价格最便宜的数字(相同价格时,自然买更大的)。参考代码:intv;cin>>v;......
  • CF467C George and Job 题解 DP 前缀和
    DP前缀和题目链接题意:给你一个长度为\(n\)的序列,让你从这个序列中挑选出\(k\)个长度为\(m\)的区间,并且任意区间不相交。使得选出的数之和最大,求出这个数。解法:很经典的DP模型,我们定义\(f_{i,j}\)表示从前\(i\)个数选出了\(j\)个区间可以取得的最大值,那么答案为:\(f_{n,k}\)。......
  • SNOI 2024 题解(坑:D1T3 D2T1 D2T2)
    树V图相同\(f(i)\)的点必然构成一个连通块,不然一定无解。每一个连通块中需要选出一个关键点,考虑相邻连通块是否合法,发现条件其实很很好判,就是两个交界点的距离需要满足某个大小关系,容易预处理后\(O(1)\)判,于是\(f_{u,x}\)表示\(u\)连通块内取\(x\)的方案数,DP即可。......