[BZOJ4408&&BZOJ4299][FJOI2016 && Codechef]神秘数&&FRBSUM(主席树)

Posted HocRiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4408&&BZOJ4299][FJOI2016 && Codechef]神秘数&&FRBSUM(主席树)相关的知识,希望对你有一定的参考价值。

 

4299: Codechef FRBSUM

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 550  Solved: 351
[Submit][Status][Discuss]

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

 

[Fjoi 2016]神秘数

时间限制:10s      空间限制:128MB

题目描述

一个可重复数字集合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

提示

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


题目来源

鸣谢yyh上传

这两题实际上是双倍经验,但我做了两遍且两遍都不会做。。

主席树非常巧妙的应用,对于一个集合S,如果S中的数可以凑出mx,那么如果向集合S中新添加一个数x,若x<=mx+1,那么加入x后S可以凑出0~mx+x的所有数,但如果x>mx+1,则x对扩大可凑出的数的范围没有作用。

这样这题就可做了,设当前已知的一定能凑出来的范围是0~mx(mx初值为0),用权值主席树快速求出区间[l,r]中所有不大于mx+1的数的和作为新的mx,如果发现mx没有增大说明mx+1就是不可凑出的数。

复杂度O(nlog^2n)

BZOJ4299:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=l; i<=r; i++)
 4 using namespace std;
 5  
 6 const int N=100010;
 7 int n,m,nd,l,r,mx,lst,a[N],rt[N],L[N*40],R[N*40],tot[N*40];
 8  
 9 void ins(int x,int &y,int l,int r,int k){
10     y=++nd; L[y]=L[x]; R[y]=R[x]; tot[y]=tot[x]+k;
11     if (l==r) return; int mid=(l+r)>>1;
12     if (k<=mid) ins(L[x],L[y],l,mid,k); else ins(R[x],R[y],mid+1,r,k);
13 }
14  
15 int que(int x,int y,int l,int r,int k){
16     if (l==r) return tot[y]-tot[x];
17     int mid=(l+r)>>1;
18     if (k<=mid) return que(L[x],L[y],l,mid,k);
19     else return tot[L[y]]-tot[L[x]]+que(R[x],R[y],mid+1,r,k);
20 }
21  
22 int main(){
23     scanf("%d",&n);
24     rep(i,1,n) scanf("%d",a+i),ins(rt[i-1],rt[i],1,1e9,a[i]);
25     for (scanf("%d",&m); m--; ){
26         scanf("%d%d",&l,&r); mx=lst=0;
27         while (1){
28             mx=que(rt[l-1],rt[r],1,1e9,mx+1);
29             if (lst==mx) break; lst=mx;
30         }
31         printf("%d\n",lst+1);
32     }
33     return 0;
34 }

BZOJ4408:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=l; i<=r; i++)
 4 using namespace std;
 5 
 6 const int N=100100,M=2000100;
 7 int n,m,l,r,nd,tot,t,ans,a[N],num[N],rt[N],sm[M],ls[M],rs[M];
 8 
 9 int find(int x){
10     int L=1,R=tot+1;
11     while (L+1<R){
12         int mid=(L+R)>>1;
13         if (x<num[mid]) R=mid; else L=mid;
14     }
15     return L;
16 }
17 
18 void ins(int y,int &x,int L,int R,int pos,int k){
19     sm[x=++nd]=sm[y]+k; ls[x]=ls[y]; rs[x]=rs[y];
20     if (L==R) return;
21     int mid=(L+R)>>1;
22     if (pos<=mid) ins(ls[y],ls[x],L,mid,pos,k); else ins(rs[y],rs[x],mid+1,R,pos,k);
23 }
24 
25 int que(int l,int r,int k){
26     int L=1,R=tot,mid,ans=0; l=rt[l-1]; r=rt[r];
27     while (L<R){
28         mid=(L+R)>>1;
29         if (k<=mid) R=mid,l=ls[l],r=ls[r];
30                 else L=mid+1,ans+=sm[ls[r]]-sm[ls[l]],l=rs[l],r=rs[r];
31     }
32     return ans+sm[r]-sm[l];
33 }
34 
35 int main(){
36     freopen("bzoj4408.in","r",stdin);
37     freopen("bzoj4408.out","w",stdout);
38     scanf("%d",&n);
39     rep(i,1,n) scanf("%d",&a[i]),num[i]=a[i]; n++;
40     sort(num+1,num+n+1); tot=unique(num+1,num+n+1)-num-1;
41     rep(i,1,n) a[i]=find(a[i]);
42     rep(i,1,n) ins(rt[i-1],rt[i],1,tot,a[i],num[a[i]]);
43     for (scanf("%d",&m); m--; ){
44         scanf("%d%d",&l,&r);
45         for (ans=1; ; ans=t+1){
46             t=que(l,r,find(ans));
47             if (t<ans) break;
48         }
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

 

以上是关于[BZOJ4408&&BZOJ4299][FJOI2016 && Codechef]神秘数&&FRBSUM(主席树)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4408: [Fjoi 2016]神秘数

BZOJ4408[Fjoi 2016]神秘数 主席树神题

BZOJ-4408神秘数 可持久化线段树

bzoj4408: [Fjoi 2016]神秘数

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

bzoj 4408: [Fjoi 2016]神秘数