• [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
    ",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
    ",ans);
    50     }
    51     return 0;
    52 }
  • 相关阅读:
    如何知道交换机的某port接入端的IP地址
    列举系统安装的所有可用的数据库提供程序
    重建需要为人民服务
    示例DataSet的构成组件,手工打造DataSet
    2009年7月31日笔记本又换了 thinkpad w500rq3
    Python体验(04)字典dictionary
    la la love on my mind
    类的继承和封装
    Oracle10gR2在Ubuntu10.10下的安装配置及链接测试
    大容量数据传输UI无响应怎么办:异步查询大结果集!
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8417008.html
Copyright © 2020-2023  润新知