题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4299

https://lydsy.com/JudgeOnline/problem.php?id=4408

(双倍经验)

题解

考虑如果直接给一个序列要求出它的神秘数应该怎么做。

对于第 \(i\) 个数,如果我们已经有了前 \(i-1\) 个数的神秘数 \(s\),那么也就是说 \([1, s - 1]\) 的正整数全部都是可以组成的。

如果 \(a_i \leq s\) 的话,那么 \([1, s - 1]\) 的数和 \(a_i\) 可以组成 \([a_i + 1, a_i + s - 1]\)。因为 \(a_i \leq s\) 所以 和之前的区间合并起来就是 \([1, a_i + s - 1]\) 所以新的 \(s\) 就是 \(s + a_i\)。

如果 \(a_i > s\),因为 \(a_i\) 无法对目前不能被表示出来的数的大小产生影响,所以 \(s\) 不变。

但是为了防止在第一种情况中的新的 \(s\) 已经被之前的第二种情况中的本来可以被表示出来的数给表示出来了,所以我们可以按照 \(a\) 从小到大的顺序处理。

那么这个时候如果遇到第二种情况其实就可以直接结束了。


考虑这个做法如何支持区间多组询问。

很容易发现,我们最后取的答案一定是把整段区间排序完以后的结果的一个前缀和的值 \(+1\),这个前缀结束的位置应该是这个前缀和 \(+1\) 的值 \(<\) 后面的第一个值的位置。

于是我们可以得到一个思路:

对于目前的前缀和 \(s - 1\),我们可以在这个区间形成的序列中找到大于这个 \(s\) 的最小的数。那么之前的数是一定可以保证 \(\leq s\) 的。然后把 \(s\) 更新为新的前缀和 \(+1\)。直到 \(s\) 不再变化为止。

重复这个过程就可以了。

可以发现 \(s\) 每做一次就会至少变大 \(2\) 倍,所以不会做超过 \(\log n\) 次。


维护的话使用主席树维护,可以方便地查询出来每一个区间的小于等于某个值的数的和。


时间复杂度 \(O(n\log^2n)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 1e5 + 7; int n, m, dis, nod;
int a[N], b[N], rt[N]; struct Node { int lc, rc, val, sum; } t[N * 18]; inline void ins(int &o, int p, int L, int R, int x) {
t[o = ++nod] = t[p], ++t[o].val, t[o].sum += b[x];
if (L == R) return;
int M = (L + R) >> 1;
if (x <= M) ins(t[o].lc, t[p].lc, L, M, x);
else ins(t[o].rc, t[p].rc, M + 1, R, x);
}
inline int qsum(int o, int p, int L, int R, int l, int r) {
if (l > r) return 0;
if (l <= L && R <= r) return t[o].sum - t[p].sum;
int M = (L + R) >> 1;
if (r <= M) return qsum(t[o].lc, t[p].lc, L, M, l, r);
if (l > M) return qsum(t[o].rc, t[p].rc, M + 1, R, l, r);
return qsum(t[o].lc, t[p].lc, L, M, l, r) + qsum(t[o].rc, t[p].rc, M + 1, R, l, r);
} inline int get(int x) { return std::upper_bound(b + 1, b + dis + 1, x) - b - 1; }
inline void lsh() {
std::sort(b + 1, b + n + 1);
dis = std::unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; ++i) a[i] = get(a[i]);
} inline void work() {
lsh();
b[++dis] = (1ll << 31) - 1;
for (int i = 1; i <= n; ++i) ins(rt[i], rt[i - 1], 1, dis, a[i]);
read(m);
while (m--) {
int l, r;
read(l), read(r);
if (l > r) std::swap(l, r);
int s = 1, tmp;
while ((tmp = qsum(rt[r], rt[l - 1], 1, dis, 1, get(s))) >= s) s = tmp + 1;
printf("%d\n", s);
}
} inline void init() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]), b[i] = a[i];
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

bzoj4408 [Fjoi 2016]神秘数 & bzoj4299 Codechef FRBSUM 主席树+二分+贪心的更多相关文章

  1. [BZOJ4408][Fjoi 2016]神秘数

    [BZOJ4408][Fjoi 2016]神秘数 试题描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1 ...

  2. BZOJ4408: [Fjoi 2016]神秘数【主席树好题】

    Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13}, 1 = 1 2 = 1+1 3 = 1+1+1 4 = 4 5 = ...

  3. BZOJ4408 [Fjoi 2016]神秘数 【主席树】

    题目链接 BZOJ4408 题解 假如我们已经求出一个集合所能凑出连续数的最大区间\([1,max]\),那么此时答案为\(max + 1\) 那么我们此时加入一个数\(x\),假若\(x > ...

  4. bzoj 4408: [Fjoi 2016]神秘数 数学 可持久化线段树 主席树

    https://www.lydsy.com/JudgeOnline/problem.php?id=4299 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1 ...

  5. BZOJ4299: Codechef FRBSUM(主席树)

    题意 题目链接 数集S的ForbiddenSum定义为无法用S的某个子集(可以为空)的和表示的最小的非负整数. 例如,S={1,1,3,7},则它的子集和中包含0(S’=∅),1(S’={1}),2( ...

  6. 【BZOJ4408】[Fjoi 2016]神秘数 主席树神题

    [BZOJ4408][Fjoi 2016]神秘数 Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1 ...

  7. Bzoj 4408: [Fjoi 2016]神秘数 可持久化线段树,神题

    4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 177  Solved: 128[Submit][Status ...

  8. BZOJ 4408: [Fjoi 2016]神秘数

    4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 464  Solved: 281[Submit][Status ...

  9. BZOJ 4408: [Fjoi 2016]神秘数 可持久化线段树

    4408: [Fjoi 2016]神秘数 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4408 Description 一个可重复数字集 ...

随机推荐

  1. React-Native 之 GD (五)属性声明和属性确认 及 占位图

    1.在 React-Native 创建的自定义组件是可以复用的,而开发过程中一个组件可能会由多个人同时开发或者多个人使用一个组件,为了让开发人员之间减少沟通成本,我们会对某些必要的属性进行属性声明,让 ...

  2. hyperworks2019x中模型简化

    Defeature→Fillets

  3. DRF 组件

    DRF组件中的认证  授权  频率限制   分页  注册器  url控件

  4. 在一个shell中查看管理 任务(前台和后台)/工作jobs 的命令

    在一个shell中查看管理 任务(前台和后台)/工作jobs 的命令 jobs是在同一个shell环境而言, 才有意义的. 为什么有jobs这个命令? 是因为, 如果从cmd line运行gui程序时 ...

  5. EDM实例之15个节日邮件标题分享

    调查显示,去年节假日,47%的消费者打开节日邮件是因为邮件主题内容吸引.为了让企业获得更多的交易,帮助企业在繁忙的节假日内不畏竞争,全国知名的EDM邮件服务商Focussend历经多年行业的实践分析, ...

  6. Django路由小知识

    from django.urls import path,re_path from app01 import views urlpatterns = [ re_path(r'^articles/200 ...

  7. docker--docker介绍

    2 docker 介绍 2.1 容器技术 在计算机的世界中,容器拥有一段漫长且传奇的历史.容器与管理程序虚拟化 (hypervisor virtualization,HV)有所不同,管理程序虚拟化通过 ...

  8. 028 (H5*) 商城实战

    目录: 正文: 1:创建项目 介绍 ESlintESLint 是一个ECMAScript/JavaScript 语法规则和代码风格的检查工具,它的目标是保证代码的一致性和避免错误. utit test ...

  9. Java 基础知识整理 (待整理)

    JVM之类加载器(ClassLoader)基本介绍 类加载器用于将class文件加载到JVM中去执行.下面介绍类加载器涉及到的基本概念和加载基本过程. 一.Java虚拟机与程序的生命周期 在运行Jav ...

  10. h2内嵌数据库使用

    参考文档 1 https://www.cnblogs.com/xdp-gacl/p/4171024.html 参考文档 2 https://blog.csdn.net/mafan121/article ...