题目传送门

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. C3P0 详解

    定义: C3P0是一个开源的JDBC连接池,目前使用它的开源项目有Hibernate,Spring等. 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”.预先在缓冲池中放入一定数量的连接,当需 ...

  2. 关闭Linux无用端口

    关闭系统不必要的端口,增强系统安全,此处以关闭111端口为例进行说明. 1).查看本机正在监听的端口: [root@b ~]# netstat -tlnup Active Internet conne ...

  3. ceph-pve英语

    adapted accordingly并相应地调整 silosn. 筒仓:粮仓:贮仓(silo的复数) saturatevt. 浸透,使湿透:使饱和,使充满While one HDD might no ...

  4. python 2和3 字符编码

    在字符编码问题上,python2 和python3 还是有点不同的.今日写篇博客,彻底理清这个问题.. 字符编码问题的由来: 这要从计算发展历史来看待这个问题了,一开始,歪果仁使用ASCII码,8位( ...

  5. spring切换环境变量——@Profile注解的使用

    在容器中如果存在同一类型的多个组件,也可以使用@Profile注解标识要获取的是哪一个bean,这在不同的环境使用不同的变量的情景特别有用.例如,开发环境.测试环境.生产环境使用不同的数据源,在不改变 ...

  6. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_03 过滤器_1_FileFilter过滤器的原理和使用

    FileFilter 需要先定义接口的实现类.并重写过滤的方法 使用 并没有起作用 过滤器的原理 缺少了a.java和b.java 如果是文件夹,就返回true,那么就会返回到Files[]数组中.然 ...

  7. Spring MVC 向页面传值-Map、Model和ModelMap https://www.cnblogs.com/caoyc/p/5635878.html

    Spring MVC 向页面传值-Map.Model和ModelMap 除了使用ModelAndView方式外.还可以使用Map.Model和ModelMap来向前台页面创造 使用后面3种方式,都是在 ...

  8. 阅读笔记09-Java程序员必备的Intellij插件

    1. .ignore 生成各种ignore文件,一键创建git ignore文件的模板,免得自己去写 地址:plugins.jetbrains.com/plugin/7495--ignore 2. l ...

  9. python3爬虫之urllib初探

    urllib主要包含request(请求模块).error(异常处理模块).parse(工具模块).robotparser(识别网站的robots.txt文件,是否允许爬取). request(请求模 ...

  10. 分享一篇Linux系统使用Tomcat服务时交互式修改server.xml中端口号的shell脚本

    #!/bin/bash echo -e '\n' echo "***********************************" port1=`grep -r "s ...