• 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
    ",ans+1);
    55     }
    56     return 0;
    57 }
  • 相关阅读:
    HDU 5120 计算两圆环相交面积
    HDU
    Dinic (邻接表实现) + 当前弧优化
    java —— static 关键字
    java —— this 关键字
    双连通分量 Road Construction POJ
    2-SAT(HDU-3062 party)
    java——构造器理解
    『题解』Codeforces1142A The Beatles
    『题解』Codeforces1142B Lynyrd Skynyrd
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/7011449.html
Copyright © 2020-2023  润新知