除了 L 神 txdy 我还能说啥呢。(L 神把这题搬模拟赛了。。。)

即把每个 x 换成 (),问是否能通过不多于一次区间反转(() 交换)后合法。

考虑怎样的括号串是合法的。

假设左括号为 \(a_p=0\),右括号为 \(a_p=1\),标号 \(0\sim n-1\)。

我们设 \(S_r=\sum_{k<r}(-1)^{a_k}\),则一个串合法当且仅当

\[S_p\ge0\land S_n=0
\]

容易发现只要 \(\{S_k\}\) 不同则不同,我们构造了一个 \(S\) 和括号串的双射。(折线法!)

现在再考虑反转操作。

假设反转 \([l,r)\)。

\[S_p\ge0\quad(p\le l)
\]
\[S_l-(S_p-S_l)\ge0\quad(l<p\le r)
\]
\[S_l-(S_r-S_l)+(S_p-S_r)\ge0\quad(r<p)
\]
\[S_l-(S_r-S_l)+(S_n-S_r)=0
\]

化简代换一下,也即

\[S_p\ge0\quad(p\le l)
\]
\[S_p\le2S_l\quad(l<p\le r)
\]
\[S_p\ge S_n\quad(r<p<n)
\]
\[S_n=2(S_r-S_l)
\]

考虑到直接 dp 可能会计重(合法的 \(l,r\) 不唯一),考虑如何避免计重。

一般来说,避免计重可以通过对条件的贪心化实现,也即对每种方案确定某种最优的 \((l,r)\) 对。

假设 \(l\sim r\) 间最大 \(S\) 为 \(S_{\max}\),容易发现 \(S_{\max}\le2S_l\)。

考虑对 \(S_n\) 分类讨论。

当 \(S_n>0\) 时,假设存在 \(S_p<0\),取 \(S_l=\lceil S_{\max}/2\rceil\) 总是不妨最优(顺带一提,\(2\le S_n\le S_r=S_l+S_n/2\le S_{\max}\le2S_l\));也即 \(2S_l-1\le S_{\max}\le2S_l\)。并且总是取最后一个可能的 \(l\),因此下次枚举到一个 \(S_p=S_l\) 时要查看 \(S_l\sim S_p\) 区间内有无 \(S<0\),倘没有则总是不得转移。可以证明这样的 \(l\) 总是最优且唯一。

区间合法遇到 \(r\) 时,我们总应使区间内最大数在 \(2S_l-1\sim2S_l\) 间,且存在 \(S_p<0\)。

由于可能会有另一个合法的 \(S_{r'}=S_r\) 在当前 \(S_r\) 后,考虑如何避免:考虑强制令到下一次出现 \(S_{r'}=S_r\) 之前有某个 \(S_p=2S_l+1\),或一直到 \(S_n\) 均无另一个 \(S_{r'}=S_r\) 则可行,否则不可行。容易发现不会漏统计情况,也不会计重。

第二类情况的计算可以考虑倒推,记录当前 \(S_r-S_n\) 和目前最大 \(S_r-S_n\),可以 \(O(n^3)\) 预处理。

对于第一类情况,即考虑枚举下次出现 \(S_p=2S_l+1\) 的时间来计算方案数,这个可以倒推预处理。通过预处理从 \(n\) 到 \(p\),保持 \(S_p-S_n\ge0\),当前 \(S_p-S_n\) 为某值的方案数,以及进一步到 \(S_v-S_n\),其间所有 \(S_l-S_n<S_k-S_n<S_p-S_n\),直至开头为某数的方案数,来暴力计算。这是 \(O(n^4)\) 的,并且很难优化。

考虑到这么做复杂度不优,我们略做修改,不枚举 \(r\),而是对区间内最大值容斥,枚举何时出现超过最大值边界的元素,这样此前所有可能的 \(S_r\) 均可以出现,从而无需对 \(r\) 端点去重。特别地,如果到终点均未出现超过边界的元素,这类贡献我们还是用先前第二类预处理的方式计算。

这样会好写一点,并且避免了复杂度不优的问题。

对于 \(S_p\ge0\) 恒成立的情况,我们考虑另写一个 dp 判断。

类似于刚刚的 dp,但是区间内不能出现与 \(S_l\) 相等的数。

考虑设 \(x\) 为最大的满足 \(S_x-S_n<0\) 的数,则取 \(r\) 为最大的满足 \(S_r-S_n=\min\{S_k-S_n|x<k\le n\}\) 即可。

只用计算这样的合法方案数即可,与上面过程是类似的。

只用找一个 \(l\) 满足 \(S_l=S_r-S_n/2\),且 \(S_{\max}\le2S_l\) 即可。显然这样的 \(l\) 越大越好,因此区间内不能有和目前 \(S_l\) 一样大的数,也即所有数均大于 \(S_l\)。

容易发现把前面的 dp 过程中未出现负数的方案也用来计算答案即可。

但是这样会算重,所以观察性质,容易发现某些情况的充要条件是 \(\max\{S_k|x<k\le n\}\ge2S_n\),然后就完了。

这样我们就讨论完了 \(S_n>0\) 的情况。

而 \(S_n<0\) 和 \(S_n>0\) 就差一个全局翻转,翻过来一样做即可。

考虑 \(S_n=0\),这个的合法条件是什么?

如果 \(S_p\ge0\) 恒成立,显然总可行。

否则,我们设 \(x\) 是第一个 \(S_x<0\),\(y\) 是最后一个 \(S_y<0\),则合法等价于

\[\max\{S_k|x\le k\le y\}\le2\min\{\max\{S_k|k<x\},\max\{S_k|k>y\}\}
\]

于是同样 dp 即可。

总复杂度容易做到 \(O(n^3)\)。

重新理一遍。

先考虑 \(S_n>0\) 的情况的答案。

由于刚刚的过程过于抽象,我们用 dp 方程来描述这一做法。

对于 \(\texttt x\),我们认为其 \(a_p\) 在过程中既可以为 \(0\),也可以为 \(1\),相当于是做两轮转移。

设 \(f_{m,v}\) 为已考虑前 \(m\) 项,其 \(S_p\ge0\) 均成立,且 \(S_m=v\) 的方案数。

显然有(\(\leftarrow\) 表示 dp 的贡献转移方向,不是赋值

\[f_{0,v}=[v=0]
\]
\[f_{m+1,v+1}\leftarrow[a_m=0]f_{m,v}
\]
\[f_{m+1,v-1}\leftarrow[a_m=1][v>0]f_{m,v}
\]

同样的,设 \(g_{m,v}\) 为已考虑 \(m\sim n\) 项,其 \(S_p-S_n\ge0\) 均成立,且 \(S_m-S_n=v\) 的方案数。

\[g_{n,v}=[v=0]
\]
\[g_{m+1,v+1}\leftarrow[a_m=1]g_{m,v}
\]
\[g_{m+1,v-1}\leftarrow[a_m=0][v>0]g_{m,v}
\]

我们类似地维护后缀、后缀最大值的 dp,方法类似。

假设 \(h_{m,L,v,0/1}\) 为已考虑 \(0\sim m\) 项,\(S_l=L\),\(S_m=v\),区间内是否已出现负数。

计算两遍,第一遍要求 \(v\le2L\),第二遍要求 \(v\le2L-2\)。

遇到 \(v>2L\) 或者 \(v>2L-2\) 的元素可以直接计算对答案的贡献,注意特判 \(L=1\)。

然后分类计算贡献即可。dp 不予列出。

\(S_p<0\) 同理。

\(S_p=0\) 的部分,分类左侧小还是右侧小,分别写一遍即可。

虽然但是,L 神 txdy!

代码写了 13k。。。

loj2839的更多相关文章

随机推荐

  1. Mattermost 笔记

    目录 部署 配置 客户端 桌面程序 Android 使用 扩展 Jenkins Hubot 机器人 Jira GitHub Mattermost 是一个开源.可私有化部署的在线通讯平台,可以和Gith ...

  2. js 非空判断

    是否为 null 是否为 "" 是否为空字符串(引号中间有空格)  如: "     ". 制表符.换行符.换页符和回车 一. 字符串 1. if(str == ...

  3. Git强制覆盖master

    场景 由于公司的项目中,有一个开发分支(这里假设dev​)是一个严重偏离master​,需要我去强制覆盖master​. 问题 这个场景带来了两个问题: ​master​是受保护不能强推 ​dev​分 ...

  4. C/C++语言 MD5例子

    之前研究了一下在C中进行MD5加密,由于找了很久没有找到现成的库文件,所以所幸自己去写了一下.个人感觉C的便捷性没有Python好的原因就是这里. 下面是我写的一个例子. mian.cpp: 点击查看 ...

  5. JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来3 —— 本地缓存变身分布式集群缓存,打破本地缓存天花板

    大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 上一篇文章中,我们知晓了如何在项目中通 ...

  6. Go语言的赞和喷

    (原发于 GitHub Pages,2019-01-01 23:22:43) 2019 年,我回来了. 不知不觉中,我入 PHP 的坑已经 3 年有余,入 Go 的坑也大半年了.作为不评论不舒服斯基星 ...

  7. 【译】15 个有用的 JavaScript 技巧

    原文地址:https://javascript.plainenglish.io/15-useful-javascript-tips-814eeba1f4fd 1)数字分隔符 为了提高数字的可读性,可以 ...

  8. FalseSharing-伪共享

    1.CPU缓存 要了解什么是伪共享,首先得了解CPU缓存架构与缓存行的知识 (1)<CPU缓存架构> 主内存RAM是数据存在的地方,CPU和主内存之间有好几级缓存,因为即使直接访问主内存相 ...

  9. strapi系列-如何创建一个定时任务-Cron Jobs

    Cron 是什么? Cron 有多种用途. Cron Jobs 用于安排服务器上的任务运行.它们最常用于自动化系统管理或维护.然而,它们也与 Web 应用程序的构建相关. Web 应用程序可能需要在各 ...

  10. vue构建打包兼容操作(vue代码规范建议)-转载Vuejs项目不改动一行代码同时支持用Rollup,vue-cli,parcel构建的一些建议