[BZOJ4408][Fjoi 2016]神秘数

试题描述

一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},
1 = 1
2 = 1+1
3 = 1+1+1
4 = 4
5 = 4+1
6 = 4+1+1
7 = 4+1+1+1
8无法表示为集合S的子集的和,故集合S的神秘数为8。
现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数。

输入

第一行一个整数n,表示数字个数。
第二行n个整数,从1编号。
第三行一个整数m,表示询问个数。
以下m行,每行一对整数l,r,表示一个询问。

输出

对于每个询问,输出一行对应的答案。

输入示例


输出示例


数据规模及约定

对于100%的数据点,n,m <= 100000,∑a[i] <= 10^9

题解

一开始把神秘数 ans 设为 1,然后大小在 [0, ans] 范围中所有数显然都是可以用的,并且它们所能组成的最大数就是所有数之和 sum,于是 ans = sum + 1,重复以上动作。因为每次 ans 至少倍增,所以操作次数不超过 9·log210。

操作可以用线段树套 treap 实现,像这样:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 100010
#define maxnode 4093490
#define LL long long
struct Node {
int v, r;
LL sum;
Node() {}
Node(int _, int __): v(_), r(__) {}
} ns[maxnode];
int ToT, fa[maxnode], ch[2][maxnode];
inline void maintain(int o) {
ns[o].sum = ns[o].v;
for(int i = 0; i < 2; i++) if(ch[i][o])
ns[o].sum += ns[ch[i][o]].sum;
return ;
}
inline void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[ch[1][z]==y][z] = u;
if(ch[1][y] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
ch[l][y] = ch[r][u]; ch[r][u] = y;
maintain(y); maintain(u);
return ;
}
inline void insert(int& o, int v) {
if(!o) {
ns[o = ++ToT] = Node(v, rand());
return maintain(o);
}
bool d = v > ns[o].v;
insert(ch[d][o], v); fa[ch[d][o]] = o;
if(ns[ch[d][o]].r > ns[o].r) {
int t = ch[d][o];
rotate(t); o = t;
}
return maintain(o);
}
inline LL que(int& o, LL v) {
if(!o) return 0;
LL ls = ch[0][o] ? ns[ch[0][o]].sum : 0;
if(v >= ns[o].v) return ls + ns[o].v + que(ch[1][o], v);
return que(ch[0][o], v);
} int rt[maxn<<2], ql, qr;
LL V;
inline void update(int L, int R, int o) {
insert(rt[o], V);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(ql <= M) update(L, M, lc);
else update(M+1, R, rc);
return ;
}
inline LL query(int L, int R, int o) {
if(ql <= L && R <= qr) return que(rt[o], V);
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
LL ans = 0;
if(ql <= M) ans += query(L, M, lc);
if(qr > M) ans += query(M+1, R, rc);
return ans;
} int main() {
int n = read();
for(int i = 1; i <= n; i++) ql = i, V = read(), update(1, n, 1); int q = read();
while(q--) {
ql = read(); qr = read();
LL ans = 0; V = ans + 1;
while(1) {
LL tmp = query(1, n, 1);
if(tmp == ans) break;
ans = tmp; V = ans + 1;
}
printf("%lld\n", ans + 1);
} return 0;
}

然后 T 飞。T_T

当然正解是主席树,代码还倍儿短。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 100010
#define maxnode 4000010
int n, m, A[maxn], sum; int ToT, root[maxn], lc[maxnode], rc[maxnode], sumv[maxnode];
void update(int& y, int x, int L, int R, int p) {
sumv[y = ++ToT] = sumv[x] + p;
if(L == R) return ;
int M = L + R >> 1; lc[y] = lc[x]; rc[y] = rc[x];
if(p <= M) update(lc[y], lc[x], L, M, p);
else update(rc[y], rc[x], M+1, R, p);
return ;
}
int query(int y, int x, int L, int R, int p) {
if(L == R) return sumv[y] - sumv[x];
int M = L + R >> 1;
if(p <= M) return query(lc[y], lc[x], L, M, p);
return sumv[lc[y]] - sumv[lc[x]] + query(rc[y], rc[x], M+1, R, p);
} int main() {
n = read();
for(int i = 1; i <= n; i++) A[i] = read(), sum += A[i];
for(int i = 1; i <= n; i++) update(root[i], root[i-1], 1, sum, A[i]);
m = read();
while(m--) {
int ql = read(), qr = read(), ans = 1;
int v = query(root[qr], root[ql-1], 1, sum, ans);
while(v >= ans) ans = v + 1, v = query(root[qr], root[ql-1], 1, sum, ans);
printf("%d\n", ans);
} return 0;
}

[BZOJ4408][Fjoi 2016]神秘数的更多相关文章

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

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

  2. bzoj4408 [Fjoi 2016]神秘数 & bzoj4299 Codechef FRBSUM 主席树+二分+贪心

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4299 https://lydsy.com/JudgeOnline/problem.php?id ...

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

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

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

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

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

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

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

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

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

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

  8. 4408: [Fjoi 2016]神秘数

    4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 452  Solved: 273 [Submit][Stat ...

  9. BZOJ4408&4299[Fjoi 2016]神秘数——主席树

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

随机推荐

  1. AC日记——校门外的树 洛谷 P1047

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  2. [译]React Context

    欢迎各位指导与讨论 : ) 前言 由于笔者英语和技术水平有限,有不足的地方恳请各位指出.我会及时修正的 O(∩_∩)O 当前React版本 15.0.1 时间 2016/4/25 正文 React一个 ...

  3. jquery.lazyload 实现图片延迟加载jquery插件

    看到了淘宝产品介绍中,图片是在下拉滚动条时加载,这是一个很不错的用户体验.减少了页面加载的时间了,也减轻了服务器的压力,就查了下用JQuery..   什么是ImageLazyLoad技术 在页面上图 ...

  4. CCPC2016沈阳站

    A.模拟 B.模拟 C(hdu5950):(矩阵快速幂) 题意:求f(n)=2f(n-2)+f(n-1)+n^4 分析:矩阵快速幂,(f(n),f(n-1),n^4,n^3,n^2,n,1) 注意:矩 ...

  5. C语言与内存模型初探

    #include<stdio.h> #include<string.h> int main(){ long long int a = 2<<30; char str ...

  6. 【Python】[面性对象编程] 获取对象信息,实例属性和类属性

    获取对象信息1.使用isinstance()判断class类型2.dir() 返回一个对象的所有属性和方法3.如果试图获取不存在的对象会抛出异常[AttributeError]4.正确利用对象内置函数 ...

  7. php 字符串和数字比较一些问题

    本文章来给大家介绍关于php 字符串和数字比较一些问题,因为数字与字符在php中是不同的数据类型,所以在比较时可能会有很多的问题. ,1,2等等,其中0标示成功,其他表示不同的错误代码.程序通过 if ...

  8. iOS对键盘的处理

    方法1. 使用<UITextFeildDelegate>,使用的UITextField示例 设置其Delegate为self,点击return按钮隐藏键盘.实现函数如下:    - (BO ...

  9. debian/deepin 15.3安装jdk 1.7 (或jdk 7),配置默认环境

    一.前言 Deepin 15.3是基于Debian开发的,安装jdk 1.7有所不同,默认是openjdk-8-jdk,而我们玩一些编译需要的是jdk 7. 所以本文给出安装JDK 7的教程. 二.安 ...

  10. jQuery中clone和clone(true)的区别

    今天要写的是clone和clone(true)的区别 两者长得很像呀,clone(true)比clone()  多了一个true.看下图白白的牙,笑起来就是这么灿烂.有了true就跟笑起来一样,有了笑 ...