CF1834E MEX of LCM

news/2024/11/8 3:06:51/

也许更好的阅读体验

D e s c r i p t i o n \mathcal{Description} Description
n n n个数,将这 n n n个数所有子区间的 l c m lcm lcm作为一个集合 S S S,求最小的没有出现在 S S S中的数 ( m e x { S } ) (mex\{S\}) mex{S}
e g : eg: eg: 3 3 3个数 1 2 3 1\ 2\ 3 1 2 3,所有子区间的 l c m lcm lcm构成集合 { 1 2 3 6 } \{1\ 2\ 3\ 6\} {1 2 3 6},第一个未出现的数是 4 4 4
n ≤ 3 ∗ 1 0 5 n\le 3*10^5 n3105 a i ≤ 1 0 9 a_i\le 10^9 ai109

S o l u t i o n \mathcal{Solution} Solution
考虑已知一个区间的 l c m lcm lcm,此时将区间往两边扩大 1 1 1 l c m lcm lcm是不降的

在知道上面之后,我们想要知道所有区间的 l c m lcm lcm中最小的未出现过数,因此我们不需要一开始就知道所有的 l c m lcm lcm,考虑按从小到大构造出 l c m lcm lcm,又知道区间 l c m lcm lcm在区间变大的过程中是一只增大的

立马就能想到用一个小根堆,最开始将每个位置上的数存进去表示以这个位置作为区间 l c m lcm lcm的起点,用 a n s ans ans表示当前考虑 a n s ans ans是否是答案,每次取出最小的数出来看是否等于 a n s ans ans,如果等于 a n s ans ans那么 a n s ans ans就不能作为答案, a n s ans ans需要增大,然后将堆顶的元素取出来让它的区间往右走一步再重新插进堆中,这样就能保证当第一次堆顶元素不等于 a n s ans ans时就找到了答案

然而这样会超时,因为会有大量的重复的计算,比如 1 , 1 , 1 , 1 , 1 , 1 ⋯ 1,1,1,1,1,1\cdots 1,1,1,1,1,1这样的序列,仅仅只是想让 a n s ans ans变成2,就需要 n 2 n^2 n2复杂度不断扩大区间

考虑什么样的情况是不需要重复计算的,当有若干个区间右端点相同,左端点不同的区间的 l c m lcm lcm相同时,只需要保留一个区间即可,例如, [ 1 , 4 ] [1,4] [1,4] l c m lcm lcm等于 [ 3 , 4 ] [3,4] [3,4] l c m lcm lcm时, [ 1 , 4 ] [1,4] [1,4]便不需要继续往右走了,因为答案会完全和 [ 3 , 4 ] [3,4] [3,4]相同

因此考虑记忆每个位置曾经出现过哪些值,当某个区间的右端点扩大后发现这个位置曾经有过区间的 l c m lcm lcm和自己相同,那么就不用将这个区间加入堆中了,用 s e t set set记忆这些值即可

C o d e \mathcal{Code} Code

#include <cstdio>
#include <queue>
#include <set>
#define ll long long
#define mp make_pair
using namespace std;
const int maxn = 3e5 + 5;
int T, n;
int x[maxn];
set <ll> now[maxn];
priority_queue < pair<ll, int> > q;
ll gcd (ll a, ll b)
{if (!b) return a;return gcd(b, a % b);
}
ll lcm (ll a, ll b){ return a * b / gcd(a, b); }
int main ()
{scanf("%d", &T);
while (T--) {scanf("%d", &n);for (int i = 1; i <= n; ++i)    scanf("%d", &x[i]), q.push(mp(-x[i], i)), now[i].clear(), now[i].insert(x[i]);ll ans = 1;while (!q.empty() && q.top().first == -ans) {while (!q.empty() && q.top().first == -ans) {ll l = -q.top().first;int i = q.top().second;q.pop();if (++i <= n) {l = lcm(l, x[i]);if (now[i].find(l) == now[i].end()) q.push(mp(-l, i)), now[i].insert(l);}}++ans;}while (!q.empty())	q.pop();printf("%lld\n", ans);
}return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧


http://www.ppmy.cn/news/752948.html

相关文章

拍照测评使用websocket

为什么拍照测评要使用ws协议来做&#xff1b; 因为要实时 返回数据 &#xff0c; 评测过程中数据能动态展示&#xff1b;比如进度条功能 、教培评测的单字评测实时渲染 拍照测评的流程 1&#xff0c;获取相机和本地相册权限 uni.getSetting({success: (res) > {// 如果没…

电脑时常断网和掉线的解决方法

一、检查网线是否松动 对于大多数宽带用户来说&#xff0c;ADSL猫接无线路由器的布网方式最为普遍&#xff0c;当出现掉线的情况&#xff0c;首先要考虑的是线路问题。 由于电话线线路过长&#xff0c;接头过多&#xff0c;或存在一些干扰源&#xff0c;很可能引发掉线&#xf…

服务器不稳定 同时登录的人太多,魔兽世界频繁掉线的三种原因及解决方法

我们在玩魔兽世界时可能会遇到频繁掉线或者长时间无法登陆的问题。很多人都不知道是什么原因导致我们玩魔兽世界时候掉线&#xff0c;也不知道采取什么方法来解决这样的问题&#xff1b;小编收集整理了导致游戏掉线的原因&#xff0c;并从电脑配置方面&#xff0c;服务器工作状…

超声波功率放大器在超声驱动技术中的应用

超声波功率放大器是一种能够将低功率信号放大到足够高的电平的电子器件。在超声驱动技术中&#xff0c;超声波功率放大器被广泛应用于超声波发生器、超声波换能器和超声波传感器等部件中&#xff0c;以保证这些部件的正常工作和高效性能。 超声波功率放大器在超声驱动技术中的应…

leetcode:面试题 递归乘法(位运算详解)

内容包括&#xff1a;题目&#xff0c;代码实现及注释&#xff0c;思路详解 目录 题目&#xff1a; 代码实现&#xff1a; 思路详解&#xff1a; 题目&#xff1a; 递归乘法。 写一个递归函数&#xff0c;不使用 * 运算符&#xff0c; 实现两个正整数的相乘。可以使用加号…

基于flask-oidc的OIDC协议授权码模式单点登录SSO实现

文章目录 安装flask-oidcflask-oidc实现OIDC的授权码模式流程代码实现依赖库安装flask-oidc认证配置获取授权码兑换token令牌 关于SSO单点登录、OIDC协议、授权码模式等相关概念详见基于OIDC的SSO单点登录文章内容 安装flask-oidc pip install flask-oidcflask-oidc实现OIDC的…

仿oppo手机浏览器首页的滑动布局

仿oppo手机浏览器首页的滑动布局 原效果图我大概实现的样子这个其实主要是一些事件分发的一些处理 周末的午后&#xff0c;我悠然的躺着床上&#xff0c;甚是无聊&#xff0c;拿起我的oppo手机&#xff0c;打开浏览器准备输入我熟悉的xxx .com&#xff0c; 忽然我发现了一个比较…

深度学习神经网络学习笔记-论文研读-transformer及代码复现参考

摘要 优势序列转导模型基于复杂的循环或包括一个编码器和一个解码器的卷积神经网络。最好的表现良好的模型还通过attention 连接编码器和解码器机制。我们提出了一种新的简单的网络架构&#xff0c;Transformer&#xff0c; 完全基于注意力机制&#xff0c;省去了递归和卷积完…