题目描述

一个可重复数字集合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,表示一个询问。

输出

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

样例输入

5
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5

样例输出

2
4
8
8
8


题解

主席树的一道神题

我们先想暴力怎么做:把一段区间的数取出来,排个序,从小到大选择。如果$a1$~$a_{i-1}$能够表示$1~x$,此时加入$a_i$,如果$a_i\le x+1$,那么就可以表示$x+a_i$,否则x就是答案。

试着优化一下这个过程:设$a_{i-1}=k$,$a_i=y$,1~i-1的神秘数为ans=x+1,那么显然$ans=\sum\limits_{t=1}^{i-1}a_t$。此时如果存在k+1~ans的数就可以更新ans。更具体地,如果k+1~ans内的数的和为s,那么ans+=s;而ans为1~k的数的和+1,故ans的新值应该赋为1~ans的数的和。

说了这么多废话有什么用?我们可以发现每次ans的增量都大于等于前一次的ans,所以这个过程的时间复杂度应该为$O(\log a)$。

而事实上我们并不能把区间拿出来排序,所以需要使用数据结构,上一个主席树就好了。

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

#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int v[N] , a[N] , root[N] , ls[N << 5] , rs[N << 5] , sum[N << 5] , tot;
void insert(int p , int l , int r , int x , int &y)
{
y = ++tot , sum[y] = sum[x] + a[p];
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) rs[y] = rs[x] , insert(p , l , mid , ls[x] , ls[y]);
else ls[y] = ls[x] , insert(p , mid + 1 , r , rs[x] , rs[y]);
}
int query(int p , int l , int r , int x , int y)
{
if(r <= p) return sum[y] - sum[x];
int mid = (l + r) >> 1;
if(p <= mid) return query(p , l , mid , ls[x] , ls[y]);
else return query(p , mid + 1 , r , rs[x] , rs[y]) + sum[ls[y]] - sum[ls[x]];
}
int main()
{
int n , m , i , x , y , ans , tmp;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , v[i] = a[i];
sort(a + 1 , a + n + 1);
for(i = 1 ; i <= n ; i ++ ) v[i] = lower_bound(a + 1 , a + n + 1 , v[i]) - a;
for(i = 1 ; i <= n ; i ++ ) insert(v[i] , 1 , n , root[i - 1] , root[i]);
a[n + 1] = 1 << 30;
scanf("%d" , &m);
while(m -- )
{
scanf("%d%d" , &x , &y) , ans = 1;
while((tmp = query(upper_bound(a + 1 , a + n + 2 , ans) - a - 1 , 1 , n , root[x - 1] , root[y])) >= ans)
ans = tmp + 1;
printf("%d\n" , ans);
}
return 0;
}

【bzoj4408】[Fjoi 2016]神秘数 主席树的更多相关文章

  1. 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 = ...

  2. BZOJ 4408: [Fjoi 2016]神秘数 [主席树]

    传送门 题意: 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},8无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]. ...

  3. BZOJ 4408: [Fjoi 2016]神秘数 主席树 + 神题

    Code: #include<bits/stdc++.h> #define lson ls[x] #define mid ((l+r)>>1) #define rson rs[ ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 用YII实现多重查询(基于tag)

    场景: 有一个饭店表 restaurant,存放所有饭店记录.我需要一个功能,将饭店按照不同的条件进行多重查询.就象这样:   氛围:浪漫 / 商务会谈 / 茅草屋 菜系:川菜 / 鲁菜 / 家常菜. ...

  2. python super详解

    一.super() 的入门使用 - 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能, 这时,我们就需要调用父类的方法了,可通过使用 super 来实 ...

  3. leecode 旋转数组

    描述 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋 ...

  4. make 与makefile(会不会写 makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。)

    跟我一起写 Makefile /**/ 陈皓 (CSDN) 概述 —— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉 ...

  5. UVA - 1279 Asteroid Rangers (动点的最小生成树)

    题意,有n个匀速动点,求最小生成树的改变次数. 一句话总结:动态问题的一般做法是先求出一个静态的解,然后求出解发生改变的事件,事件按照时间排序,依次处理. 先求出最开始的最小生成树(MST),当MST ...

  6. Objective-C相关Category的收集(更新)

    Categories是给你得不到源码的classes增加功能的一种方法.这个页面收集一些相关的Category,并且持续更新,你可以订阅关注.作者是Fille ?str?m,是@ IMGNRY的联合创 ...

  7. C04 模块化开发

    目录 模块化开发概述 函数概述 如何使用函数 字符串处理函数 模块化开发特点 模块化开发概述 概述 C语言是面向过程的语言,意味着编写C语言程序的时候,我们要像计算机一样思考如何设计程序. 模块化开发 ...

  8. webuploader项目中多文件上传实例

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  9. Noip2018 考前准备

    目录 基础算法 二分 模拟(未补) 高精(未学习) 搜索(未补) 排序 图论 树的直径 树的重心 最短路算法 Spfa Dijkstra Floyd 最小生成树 kruskal 数论 线性筛 线性筛素 ...

  10. 初涉KMP算法

    久仰字符串系列理论 KMP 讲解(引用自bzoj3670动物园) 某天,园长给动物们讲解KMP算法. 园长:“对于一个字符串S,它的长度为L.我们可以在O(L)的时间内,求出一个名为next的数组.有 ...