1 条题解
-
0
自动搬运
来自洛谷,原作者为

cyffff
Not yet for the story on the last page, it's not the end.搬运于
2025-08-24 22:33:16,当前版本为作者最后更新于2021-02-22 16:55:52,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
算法 1
针对 。
显然对于询问 ,答案为 ,对于询问 ,答案为 。
时间复杂度 。期望得分 。
算法 2
暴力求区间最长不降/上升子序列,时间复杂度 。期望得分 ,结合算法 可得 。
算法 3
设 ,(,)。
第一问:
其实本质是求 $\max_{i=l}^r pre_{0,i}-pre_{0,l-1}+pre_{1,r}-pre_{1,i}$。
怎么理解这个柿子呢?显然 是前缀和的形式,所以 即 , 即 。我们可以理解 为分界线,分界线前选 ,分界线后选 ,枚举所有 ,显然可以取到最大值,时间复杂度 。
还需要特判只选 的情况,当然你也可以看为求 $\displaystyle\max_{i=l-1}^rpre_{0,i}-pre_{0,l-1}+pre_{1,r}-pre_{1,i}$。
第二问:
显然有答案为 或 ,答案为 时只有在有 在最后一个 前面,否则为 。
于是我们考虑维护 为 时 前最后一个 所在的位置,否则为 。
答案显然为 ,暴力枚举,时间复杂度 。
总时间复杂度 。期望得分 。
算法 4
上面那个东西可以套路ST表处理,时间复杂度 ,期望得分 。
当然开 个ST表常数较大。
用
+1-1RMQ可以做到严格 ,常数较大,不做为本题最优做法。这里还有一个后来发现的一个减小常数方法:
发现第二问只有 和 两种答案,要有 则区间中必须出现连续的 ,于是我们维护 出现次数的前缀和,如果左端点前缀和等于右端点前缀和,则答案为 ,否则为 。可以大大减小常数,如果实现优秀,则可以所有点进 1s。
#include<bits/stdc++.h> using namespace std; namespace IO{//by cyffff } const int N=1e6+10; int n,m,st[20][N],lg[N],a[N],pre[N],pp[N]; inline int query(int l,int r){ int q=lg[r-l+1]; return max(st[q][l],st[q][r-(1<<q)+1]); } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++){ a[i]=read(); } a[0]=2; int sum=0,o=0,z=0; for(int i=1;i<=n;i++){ if(a[i]) sum--,o++; else sum++,z++; st[0][i]=z-o; pp[i]=o; pre[i]=pre[i-1]+(a[i]==1&&a[i-1]==0); } for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=19;i++) for(int j=1;j+(1<<i)-1<=n;j++) st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]); for(int i=1;i<=m;i++){ int opt=read(),l=read(),r=read(); if(opt==1) write(max(pp[r]-pp[l-1],query(l,r)-(l-1-pp[l-1])+pp[r])); else write(1+!(pre[l]==pre[r])); putc('\n'); } flush(); return 0; }再见 qwq~
upd:好像赛时还被线段树过了,考虑加入主题库后缩小时限。
- 1
信息
- ID
- 6519
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者