CF145E Lucky Queries 题解
题目链接: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\) 的特殊情况中了。
\(mid\) 放在了某个 \(0\) 上,那么将原串分割为 \(000\) 与 \(000011111\),前者为左区间的串,显然最优为 \(LIS\) 时,应该取 \(0\) 的数量,后面要求 \(01\) 串这种连续串最长,显而易见是右区间的 \(LIS\)。符合我们说的其中一个情况:\(Zero_{left}+LIS_{right}\)。
\(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;
}
\]
CF145E Lucky Queries 题解的更多相关文章
- CF145E Lucky Queries
CF145E Lucky Queries 英文题面不放了,直接上翻译: 题目描述 给你n个数,每个数是4或者7,给你m个任务完成 switch l r 把[l,r]位置的4换成7,7换成4 count ...
- 数据结构(线段树):CodeForces 145E Lucky Queries
E. Lucky Queries time limit per test 3 seconds memory limit per test 256 megabytes input standard in ...
- Codeforces 145E Lucky Queries 线段树
Lucky Queries 感觉是很简单的区间合并, 但是好像我写的比较麻烦. #include<bits/stdc++.h> #define LL long long #define f ...
- [CF1093G]Multidimensional Queries 题解
前言 DennyQi太巨了! 定义一个点\(a\),\(a_x\)表示\(a\)在第\(x\)维空间上的坐标值 题解 这题的思路珂以说非常巧妙(原谅我又用了这个"珂"), 我们知道 ...
- CF375D Tree and Queries 题解
感觉CF的题目名都好朴素的样子 你谷链接 首先这题显然是个dsu on tree 但是我不会. 其次这题显然是个莫队.这我会啊! 然后会发现好像不是很对劲.因为每次询问都有一个k,貌似和传统的莫队数颜 ...
- LuoguP7059 [NWRRC2015]Lucky Chances 题解
Content 有一个名叫 Lucky chances 的游戏,游戏一开始给出一个 \(r\times c\) 的矩阵,你可以选定矩阵中任意一个元素以及上.下.左.右四个方向中的任意一个方向进行游戏. ...
- CF808A Lucky Year 题解
Content 年份中有不超过 \(1\) 个非 \(0\) 数字的年份是幸运年份.现给出当前年份 \(n\),求到下一个幸运年份还要等多久. 数据范围:\(1\leqslant n\leqslant ...
- 2015浙江财经大学ACM有奖周赛(一) 题解报告
2015浙江财经大学ACM有奖周赛(一) 题解报告 命题:丽丽&&黑鸡 这是命题者原话. 题目涉及的知识面比较广泛,有深度优先搜索.广度优先搜索.数学题.几何题.贪心算法.枚举.二进制 ...
- Codeforces Round #104 (Div. 1)
A.Lucky Conversion 题意 给定两个长度为 \(N(N \le 10^5)\) 且由4和7构成的 \(a, b\)串 对 \(a\) 可以有两种操作: 交换两个位置的字符; 改变一个位 ...
- codeforcess水题100道
之所以在codeforces上找这100道水题的原因是为了巩固我对最近学的编程语言的掌握程度. 找的方式在codeforces上的PROBLEMSET中过的题最多的那些题里面出现的最前面的10个题型, ...
随机推荐
- mouseenter和mouseover区别
mouseenter事件 当鼠标移动到元素上时,就会触发mouseenter事件. 类似mouseover,它们两者之间的差别是:mouseover鼠标经过自身盒子会触发,经过子盒子还会触发.mous ...
- 解决 idea maven plugins 报红波浪线
导入新项目到 idea 的时候,由于依赖的环境以及项目中 maven 编译所依赖的pom的版本不同,很多时候导入到idea的时候 maven Plugins 会出现报红的情况,这是由于maven仓库中 ...
- Feign拦截器和解码器
一.业务需求 在Spring Cloud的项目中,A服务使用Feign调用B服务的某个接口,如果需要传递全局认证token或参数,在方法参数里面加相应字段的方式显然是不可取的. 首先想到的是AOP方式 ...
- [转帖]CPU写入512bit要多久:从AVX到NEON
https://zhuanlan.zhihu.com/p/677124882 写这篇文章的原因是有个项目需要降低延迟,希望能更快地把512bit的数据从内存搬进PCIe设备.原先的做法是软件写寄存器通 ...
- 银河麒麟上面 ntopng的安装与使用
银河麒麟上面 ntopng的安装与使用 背景 一直想用Grafana监控网络流量 但是断断续续尝试了一周的时间都没有搞定. 发现这一块已经进入了瓶颈. 比较无奈的情况下回到了原来的iftop/iptr ...
- 监控服务器所有磁盘的inode使用情况
监控服务器所有磁盘的inode使用情况 背景 因为前期数据库开启了审计 但是如果是 DB模式的话 $aud 表的冲突和使用太多了 所以专家建议将审计表放到OS 因为数据库的访问量特别高. 审计的信息又 ...
- [转帖]TiUP 常见运维操作
https://docs.pingcap.com/zh/tidb/stable/maintain-tidb-using-tiup 本文介绍了使用 TiUP 运维 TiDB 集群的常见操作,包括查看集群 ...
- [转帖]etcd raft模块解析
https://www.cnblogs.com/luohaixian/p/16641100.html 1. Raft简介 raft是一个管理复制式日志的共识算法,它是通过复制日志的方式来保持状态机里的 ...
- [转帖]陈巍谈芯:NLP里比BERT更优秀的XLNet长什么样?
https://zhuanlan.zhihu.com/p/447836322 目录 收起 一.XLNet的优势 1)独得AR与AE两大绝学 2)集成了Tansformer-XL 二.XLNet的结 ...
- Sysbench的简单学习-编译与安装
sysbench的简单学习-编译与安装 摘要 github上面获取一下最新版本 https://github.com/akopytov/sysbench 注意现在 2023.2.17 最新版是 sys ...