zoukankan      html  css  js  c++  java
  • Bzoj4408--Fjoi2016神秘数

    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

    对于每个询问,输出一行对应的答案。

    题解 :

    什么数会不能组成出来,就是在这个区间里所有小于这个数的和小于这个数的时候

    那么我们要找的就是第一个小于这个数的所有数的和小于这个数的数

    对于一个区间,我们求所有小于等于x的和,设为S,那么由于递推计算这个区间可以组成所有小于等于S的数,然后我们再计算所有小于等于S的数的和,这样迭代计算

    当出现小于等于S的数的和等于S时说明S+1就是我们要找的数

    具体迭代计算可以用主席树

    复杂度证明 :

    因为x有可能没在区间中出现过,所以我们设pre(x)为区间中小于x的第一个数

    当我们求出所有小于等于x的数的和S,再去求所有小于等于S的数的和T时,迭代到第三步如果没有停止,那么T>2*pre(x)

    因为S>=pre(x),而迭代到T若还未停止说明区间中存在pre(x)<ai<=S;那么T相比两步前的x至少扩大2倍

    所以迭代次数最多不超过2*log(n)次

    总复杂度(nlogn)

    代码 : 

    #include<bits/stdc++.h>
    #define LL long long
    #define INF 1000000000
    using namespace std;
    
    #define MAXN 100005
    
    const int L=0,R=1;
    int n,m,s[MAXN];
    int son[MAXN*33][2],sum[MAXN*33],root[MAXN],sz;
    
    void Build(int l,int r,int v,int fr,int &now) {
        now=++sz;
        son[now][L]=son[fr][L];
        son[now][R]=son[fr][R];
        sum[now]=sum[fr]+v;
        if(l==r) return;
        int mid=l+r>>1;
        if(v>mid) Build(mid+1,r,v,son[fr][R],son[now][R]);
        else Build(l,mid,v,son[fr][L],son[now][L]);
    }
    
    int Qurey(int l,int r,int nl,int nr,int x,int y) {
        if(l==nl&&r==nr) return sum[y]-sum[x];
        int mid=l+r>>1;
        if(nl>mid) return Qurey(mid+1,r,nl,nr,son[x][R],son[y][R]);
        else if(nr<=mid) return Qurey(l,mid,nl,nr,son[x][L],son[y][L]);
        else return Qurey(l,mid,nl,mid,son[x][L],son[y][L])+Qurey(mid+1,r,mid+1,nr,son[x][R],son[y][R]);
    }
    
    int Solve(int l,int r) {
        int eni=1,t;
        while((t=Qurey(1,INF,1,eni,root[l-1],root[r])+1)>eni) {
            eni=t;
        }
        return t;
    }
    
    int main() {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) {
            scanf("%d",&s[i]);Build(1,INF,s[i],root[i-1],root[i]);
        }
        scanf("%d",&m);
        for(int l,r,i=1;i<=m;i++) {
            scanf("%d%d",&l,&r);
            printf("%d
    ",Solve(l,r));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Python中文乱码
    Python读写Excel
    Image File Execution Options(2)
    Image File Execution Options(转)
    IndentationError: unexpected indent python
    java中class.forName和classLoader加载类的区分
    vi 新建编辑文件时报错 E212 can’t open file for writing
    JAVA NIO 之ByteBuffer的mark、position、limit、flip、reset,get方法介绍
    从0x00到0xFF的含义以及二进制到10进制的转换(转)
    java匿名内部类之RocketMQ中的应用
  • 原文地址:https://www.cnblogs.com/ihopenot/p/6179880.html
Copyright © 2011-2022 走看看