当前位置: 首页 > news >正文

题解:AT_wtf22_day2_b The Greatest Two

神仙题。官方题解搬运工,尽量加上自己的理解使得这篇题解更好理解。

题意:

首先会发现,每个数只要在一个区间 \([l_v,r_v]\) 中那么一定有解,并且一定是 \(v\) 更大的会套住 \(v\) 更小的形成一个树形结构。有点反直觉但是手玩一下确实是对的。

先考虑怎么计算,如果有这个的话直接从小到大扫一遍,计算 \((r_v-l_v+1-[t<v且l_v\le l_t\le r_t\le r_v 的个数])\)

考虑证明这个东西,我们将在给出算法的同时说明这个事情。

我们考虑从 \(v\) 小到大进行建立,假设我们已经完成了 \(v=m\) 的建立,现在我们要建立 \(v=m + 1\),我们可以先找到已经建立的包含 \(p_v\) 的区间,\(p_v\) 是数 \(v\) 的下标。

那么考虑现在这个区间 \([L,R]\),我们尝试去扩展这个区间,我们先认为 \(>m+1\) 的都可以随意重排,反正可以交换的情况是对于 \(v=m +1\) 没有区别。

对于 \(L\) 右侧的数,我们需要满足这些条件:

  • 对于 \(v=m+1\),我们希望他尽量接近 \(L\)

  • 对于 \(v\le m\),我们希望他在第一条的前提下尽量靠近 \(L\)

对于 \(L\) 左侧:

  • 有恰好一个 \(>v\) 的数接近 \(L\)

  • 对于 \(v\le m\),我们希望他在第一条的前提下尽量靠近 \(L\)

然后如果这样能交换,那么就说明我们可以跨过 \(L\)

但是显然这些条件还不够,太难判断了。但是我们注意到 \([L,R]\) 区间内的数一定不能放出去,所以对于右侧的第二条限制,其实等同于我们尽量往左放,左侧的同理。

那么其实我们再考虑 \(v=m+1\),我们要让他尽量接近 \(L\),其实等于我们所有 \(v\le m\) 的尽量往右放,给我的 \(v=m+1\) 去腾出来位置让他尽量接近,对于左侧需要的 \(v>m+1\) 的同理。

但是这里还有一个特殊的情况,如果左侧的尽量往右放,右侧的尽量往左放之后,我的整个区间并没有 \(K\) 长,那么显然也是不能交换的。这里注意,因为我只需要没有第二个 \(v>m+1\) 的出现,所以对于未放置的第二个之前的都可以使用,而不是未放置第一个之前的。

根据这个算法,因为我们可以控制 \(v\le m\) 的放置来控制我交换到的位置,所以我们确实说明了可交换到的是一个区间且可以随便放。

然后根据上述过程去维护,我这里用的是 set,那么就可以在 \(O(n\log n)\) 的时间解决。

结合代码应该会更好理解一些:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2.5e5 + 5, mod = 998244353;
int a[maxn], p[maxn], n, k;
#define lowbit(x) (x & (-x))
struct Tree_array {int tr[maxn];void add(int x, int val) {while(x <= n)tr[x] += val, x += lowbit(x);}int query(int x) {int ans = 0;while(x)ans += tr[x], x -= lowbit(x);return ans;}
} tree;
set<int> s, tor, tol; //目前剩下的端点,全部尽量往右放还剩下的位置,往左放剩下的
bool chk(int x) { // 判断是否可以经过 [x-1,x]int rx = *tor.lower_bound(x), ry = *++tol.lower_bound(x); // 尽量往右放,第一个还可以放的位置;尽量往左放,只要不碰到第二个 v > m + 1 的都可以取int lx = *--tol.lower_bound(x), ly = *----tor.lower_bound(x);if(rx <= n && lx >= 1 && rx - lx < k && ry - ly - 1 - 2 >= k - 2) //保证两个位置之间至少 < k可以操作,并且有足够多的填入return 1;return 0;
}
signed main() {cin >> n >> k;for (int i = 1; i <= n; i++)cin >> a[i], p[a[i]] = i;for (int i = 0; i <= n + 1; i++)s.insert(i), tol.insert(i), tor.insert(i);int ans = 1;for (int i = 1; i <= n; i++) {set<int>::iterator itl = --s.upper_bound(p[i]), itr = s.upper_bound(p[i]);while(chk(*itl))itl = --s.erase(itl);while(chk(*itr))itr = s.erase(itr);tor.erase(--tor.lower_bound(*itr)), tol.erase(tol.lower_bound(*itl)); // 往右往左放ans = ans * (*itr - *itl - (tree.query(*itr - 1) - tree.query(*itl - 1))) % mod;tree.add(p[i], 1);}cout << ans << endl;return 0;
}
http://www.hskmm.com/?act=detail&tid=24027

相关文章:

  • 威胁狩猎实战:终端攻击行为分析与检测
  • 实用指南:基于Hadoop+Spark的人体体能数据分析与可视化系统开源实现
  • 英语_阅读_Water Sliding_待读
  • 实用指南:ArcGIS JSAPI 高级教程 - 高亮效果优化之开启使用多高亮样式
  • const在for用不了
  • about me
  • 10月北京中学集训随笔
  • 使用100%缩放比例重新启动Visual Studio 界面模糊的解决方案
  • 某工程师入职华为,职级比较高,但还看不懂代码,有点尴尬
  • 使用Silobase在几分钟内快速部署后端API
  • 【光照】[各向异性]在UnityURP中的实现
  • 基于HAL库和中断的LED流水灯
  • 从衡阳麻衣事件到AI元人文:用户端元人文实践的进化路径研究——声明ai研究
  • 5_flutter UI框架选型
  • 4_查询flutter版本信息
  • 3_flutter简单教程
  • 如何给 Claude 中的网页做截图
  • 2_gradle配置加速
  • AI元人文:岐金兰《悬鉴》起源
  • 九月回忆
  • PWN手成长之路-07-bjdctf_2020_babystack2-栈溢出+整型溢出
  • jellyfine-code1008播放器无法实例化错误、群晖系统分区空间不足解决办法
  • 将GitHub项目克隆后在本地修改好后如何同时提交到GitHub和Gitee
  • MySQL.Data.DLL 官网下载方法 2025
  • 宣泄情绪
  • 执行一次 git commit 后,本地的这次提交能同时推送到 GitHub 和 Gitee 两个远程仓库
  • 【一起学rust | 基础篇】环境配置
  • QWEN
  • 趣题记
  • Day25捕获与抛出异常