版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/82930461
洛谷传送门
BZOJ传送门
题目描述
一个可重复数字集合 的神秘数定义为最小的不能被 的子集的和表示的正整数。例如 ,
无法表示为集合 的子集的和,故集合 的神秘数为 。
现给定 个正整数 , 个询问,每次询问给定一个区间 ,求由 所构成的可重复数字集合的神秘数。
输入输出格式
输入格式:
第一行一个整数 ,表示数字个数。
第二行 个整数,从 编号。
第三行一个整数 ,表示询问个数。
以下 行,每行一对整数 ,表示一个询问。
输出格式:
对于每个询问,输出一行对应的答案。
输入输出样例
输入样例#1:
5
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5
输出样例#1:
2
4
8
8
8
说明
对于100%的数据点,$n,m \le 100000 ∑a[i] \le 10^9$
解题分析
这道题的思路来自于一个很显然的结论: 从 开始递推, 如果 的数凑出来, 那么 也能凑出来。 这样搞我们用主席树维护, 每次 至少增大一倍, 总复杂度就是 的。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int dot, q, cnt, dif;
struct Node {int sum, son[2];} tree[MX * 40];
int root[MX], buf[MX], dat[MX];
namespace SGT
{
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define pls tree[pre].son[0]
#define prs tree[pre].son[1]
void insert(R int pre, int &now, R int lef, R int rig, R int tar, R int val)
{
now = ++cnt; tree[now] = tree[pre]; tree[now].sum += val;
if(lef == rig) return;
int mid = lef + rig >> 1;
if(tar <= mid) insert(pls, ls, lef, mid, tar, val);
else insert(prs, rs, mid + 1, rig, tar, val);
}
int query(R int pre, R int now, R int lef, R int rig, R int bd)
{
if(rig <= bd) return tree[now].sum - tree[pre].sum;
int mid = lef + rig >> 1;
int ret = query(pls, ls, lef, mid, bd);
if(bd > mid) ret += query(prs, rs, mid + 1, rig, bd);
return ret;
}
}
IN int getid(R int now) {int k = std::lower_bound(buf + 1, buf + 1 + dif, now) - buf; if(buf[k] > now) k--; return k;}
int main(void)
{
int a, b, ans, pos, sum;
in(dot);
for (R int i = 1; i <= dot; ++i) in(dat[i]), buf[i] = dat[i];
std::sort(buf + 1, buf + 1 + dot); dif = std::unique(buf + 1, buf + 1 + dot) - buf - 1;
for (R int i = 1; i <= dot; ++i) SGT::insert(root[i - 1], root[i], 1, dif, getid(dat[i]), dat[i]);
in(q);
W(q--)
{
in(a), in(b);
ans = 1;
W(233)
{
sum = SGT::query(root[a - 1], root[b], 1, dif, getid(ans));
if(sum >= ans) ans = sum + 1;
else break;
}
printf("%d\n", ans);
}
}