• BZOJ4408: [Fj Winter Camp 2016]神秘数


    Description

    一个可重复数字集合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]所构成的可重复数字集合的神秘数。

    Input

    第一行一个整数n,表示数字个数。
    第二行n个整数,从1编号。
    第三行一个整数m,表示询问个数。
    以下m行,每行一对整数l,r,表示一个询问。

    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%的数据点,n,m <= 100000,∑a[i] <= 10^9

     
    我们先来考虑一个简单的问题,给定一个集合S,怎么求它的神秘数。
    我们可以将S从小到大排序,设当前的神秘数为ans,即[1,ans-1]的所有数都能用S的子集和表示而ans不能用S的子集和表示。
    那么将一个v加入S中,那么[v,ans+v-1]的所有数都可以用S表示了。
    那么可以发现一个神奇的事情:
    当v<=ans时,ans+=v。
    当v>ans时,ans不变。
    那么将这个算法拓展到区间上,ans从1开始,每次计算该区间中大小在[1,ans]的数之和为v,则赋值ans=v+1。
    因为ans每次至少翻一倍,最多logn次迭代。
    然后用主席树来维护一下就好了。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=100010;
    const int maxnode=3500010;
    int n,m,sum,root[maxn],A[maxn],sumv[maxnode],ls[maxnode],rs[maxnode],ToT;
    void update(int& y,int x,int l,int r,int pos) {
        sumv[y=++ToT]=sumv[x]+pos;
        if(l==r) return;int mid=l+r>>1;
        ls[y]=ls[x];rs[y]=rs[x];
        if(pos<=mid) update(ls[y],ls[x],l,mid,pos);
        else update(rs[y],rs[x],mid+1,r,pos);
    }
    int query(int y,int x,int l,int r,int pos) {
        if(l==r) return sumv[y]-sumv[x];
        int mid=l+r>>1;
        if(pos<=mid) return query(ls[y],ls[x],l,mid,pos);
        return query(rs[y],rs[x],mid+1,r,pos)+sumv[ls[y]]-sumv[ls[x]];
    }
    int query(int x,int y) {
        int ans=1;
        for(int t;;ans=t+1) {
            if((t=query(root[y],root[x],0,sum,ans))<ans) break;
        }
        return ans;
    }
    int main() {
        n=read();sum=0;
        rep(i,1,n) A[i]=read(),sum+=A[i];
        rep(i,1,n) update(root[i],root[i-1],0,sum,A[i]);
        m=read();
        rep(i,1,m) {
            int l=read(),r=read();
            printf("%d
    ",query(l-1,r));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    JavaScript面向对象基础语法总结
    json对象
    关于JavaScript语法的小笔记
    关于JavaScript的小笔记
    html中的a标签的target属性的四个值的区别?
    详解Bootstrap 定义按钮的样式(CSS)
    (负)-margin在页面布局中的应用
    lorem ipsum text占位符
    jQuery动态添加元素事件
    实用|从0到1 搭建Web性能监控系统
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5227889.html
Copyright © 2020-2023  润新知