Bzoj4299 Codechef FRBSUM

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 416  Solved: 276

Description

数集S的ForbiddenSum定义为无法用S的某个子集(可以为空)的和表示的最小的非负整数。
例如,S={1,1,3,7},则它的子集和中包含0(S’=∅),1(S’={1}),2(S’={1,1}),3(S’={3}),4(S’={1,3}),5(S' = {1, 1, 3}),但是它无法得到6。因此S的ForbiddenSum为6。
给定一个序列A,你的任务是回答该数列的一些子区间所形成的数集的ForbiddenSum是多少。
 

 

Input

输入数据的第一行包含一个整数N,表示序列的长度。
接下来一行包含N个数,表示给定的序列A(从1标号)。
接下来一行包含一个整数M,表示询问的组数。
接下来M行,每行一对整数,表示一组询问。
 

 

Output

对于每组询问,输出一行表示对应的答案。
 

 

Sample Input

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

Sample Output

2
4
8
8
8

HINT

 

对于100%的数据,1≤N,M≤100000,1≤A_i≤10^9,1≤A_1+A_2+…+A_N≤10^9。


 

 

Source

 

线段树 主席树 脑洞题

 

又是很神奇的结论题?

给定一个数列,假如我们现在可以用数列中的数凑出$[1,x]$范围内的所有数,若是能从数列中再找到一个$[1,x+1]$范围内的数,我们就可以凑出$[1,x+1]$范围的所有数。而如果我们只能再找到大于x+1的数,那么就无法继续凑了,最终答案是x+1 。

按照这个思想,我们可以提取出询问区间内的数,从小到大尝试答案:

  设当前可以凑出$[1,res]$范围。统计所有小于等于res+1的数的和sum,若$ sum>=res+1 $,说明我们可以凑出[1,sum]范围的数。

  令res=sum,继续尝试扩大范围。

我们发现如果每次区间都能扩大,至少会扩大为原来的两倍,可以在$O(log(n))$的时间内回答一个询问。

具体的查询可以用主席树维护。

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #define LL long long
 7 using namespace std;
 8 const int INF=1e9;
 9 const int mxn=100010;
10 int read(){
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 struct node{
17     int l,r;int smm;
18 }t[mxn*60];
19 int rot[mxn],cnt=0;
20 #define lc t[rt].l
21 #define rc t[rt].r
22 void update(int p,int v,int l,int r,int y,int &rt){
23     rt=++cnt;
24     t[rt]=t[y];
25     t[rt].smm+=v;
26     if(l==r)return;
27     int mid=(l+r)>>1;
28     if(p<=mid)update(p,v,l,mid,t[y].l,lc);
29     else update(p,v,mid+1,r,t[y].r,rc);
30     return;
31 }
32 int query(int R,int l,int r,int y,int rt){
33     if(r<=R){return t[rt].smm-t[y].smm;}
34     int mid=(l+r)>>1;
35     if(R<=mid)return query(R,l,mid,t[y].l,lc);
36     return query(R,l,mid,t[y].l,lc)+query(R,mid+1,r,t[y].r,rc);
37 }
38 int n,m;
39 int a[mxn];
40 int main(){
41     int i,j;
42     n=read();
43     for(i=1;i<=n;i++)a[i]=read();
44     for(i=1;i<=n;i++)update(a[i],a[i],1,1e9,rot[i-1],rot[i]);
45     m=read();
46     int L,R,ans=1;
47     while(m--){
48         L=read();R=read();int res=1;
49         ans=min(INF,query(res,1,1e9,rot[L-1],rot[R]));
50         while(ans>=res && res<1e9){
51             res=ans+1;
52             ans=min(INF,query(res,1,1e9,rot[L-1],rot[R]));
53         }
54         printf("%d\n",ans+1);
55     }
56     return 0;
57 }

 

posted @ 2017-06-14 22:36  SilverNebula  阅读(155)  评论(0编辑  收藏  举报
AmazingCounters.com