●BZOJ BZOJ 4408 [Fjoi 2016]神秘数

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=4408

题解:

主席树

首先,对于一些数来说,

如果可以我们可以使得其中的某些数能够拼出 1~ret

那么此时的ANS(神秘数)= ret+1

然后考虑,如果此时存在另一个数小于等于 ANS,(设该数为 x)

则一定可以在原来的1~ret的基础上拼出 1~ret+x

即 ANS 可以更新为 ret+x+1

所以具体的操作就是:

每次查询区间内小于ANS的数的和(SUM),然后如果SUM大于ANS,则更新ANS为SUM+1。

不断上述操作直到SUM<ANS为止。

主席数实现在序列区间中查询权值区间的和。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100500
using namespace std;
int A[MAXN],tmp[MAXN];
int N,M,tnt;
struct CMT{
    long long sum[MAXN*20];
    int rt[MAXN],ls[MAXN*20],rs[MAXN*20],sz;
    void Insert(int v,int &u,int l,int r,int p){
        u=++sz; ls[u]=ls[v]; rs[u]=rs[v];
        sum[u]=sum[v]; sum[u]+=tmp[p];
        if(l==r) return;
        int mid=(l+r)>>1;
        if(p<=mid) Insert(ls[v],ls[u],l,mid,p);
        else Insert(rs[v],rs[u],mid+1,r,p);
    }
    long long Query(int v,int u,int l,int r,int al,int ar){
        if(al<=l&&r<=ar) return sum[u]-sum[v];
        int mid=(l+r)>>1; long long ret=0;
        if(al<=mid) ret+=Query(ls[v],ls[u],l,mid,al,ar);
        if(mid<ar) ret+=Query(rs[v],rs[u],mid+1,r,al,ar);
        return ret;
    }
    void Build(){
        for(int i=1;i<=N;i++)
            Insert(rt[i-1],rt[i],1,tnt,A[i]);
    }
}DT;
int main(){
//  freopen("/home/noilinux/Documents/Code/BZOJ/4408.in","r",stdin);
//  printf("BEGIN.\n");
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
        scanf("%d",&A[i]),tmp[i]=A[i];
    sort(tmp+1,tmp+N+1);
    tnt=unique(tmp+1,tmp+N+1)-tmp-1;
    for(int i=1;i<=N;i++)
        A[i]=lower_bound(tmp+1,tmp+tnt+1,A[i])-tmp;
    scanf("%d",&M);
    DT.Build(); long long ANS,ret,p;
    for(int i=1,l,r;ANS=0,ret=0,i<=M;i++){
        scanf("%d%d",&l,&r);
        while(ANS<ret+1){
            ANS=ret+1;
            p=upper_bound(tmp+1,tmp+tnt+1,ANS)-tmp-1;
            ret=DT.Query(DT.rt[l-1],DT.rt[r],1,tnt,1,p);
        }
        printf("%lld\n",ANS);
    }
    return 0;
}

  

时间: 2024-08-13 16:33:44

●BZOJ BZOJ 4408 [Fjoi 2016]神秘数的相关文章

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

4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 177  Solved: 128[Submit][Status][Discuss] 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的子集的

bzoj 4408: [Fjoi 2016]神秘数

额,一开始突然想到了如果能表示出连续的二进制位,就可以构造出连续的数了..然后想了一下,不可做2333 于是又走上了扒题解的不归路.. 貌似题解就是推广一下?? 如果能表示出[l,r]那么新加入一个数a,那么可以得到一个新的区间是[l+a,r+a],然后和 [l,r]and[l+a,r+a](and表示取并集)就是现在能表示的区间. 现在我们希望 [l,r]and[l+a,r+a]==[l,r+a] ,这样的话考虑a的加入顺序,显然是应该从小到大的. 而且,在[l,r]and[l+a,r+a]=

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

[BZOJ4408][Fjoi 2016]神秘数 Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+17 = 4+1+1+18无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数

【bzoj4408】[Fjoi 2016]神秘数 主席树

题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+17 = 4+1+1+18无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数. 输入 第一行一个整数n,表示数字个数.第二行n个整数,从1编

bzoj4408: [Fjoi 2016]神秘数

题意:给n个数,定义一段区间神秘数为该区间所有数字通过组合相加所能得到的数的mex,m个询问,对于区间[l,r]询问该区间的神秘树. 如果我们将这段数排序,并且已知前n个数的神秘数为x,即现在凑得的数的区间为[1,x],新加入的数为a,那么不难发现,我们凑得的数又得到了一段区间[a+1,a+x],那么如果a+1<=x,我们就可以拼上这两段,而神秘数变为a+x+1. 也即是说,我们有当前解ans,我们将所有小等ans的数加起来(其实根据前面所推应该是小于,但是写小等不会错,而且对于代码来说更好些,

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

4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 475  Solved: 287[Submit][Status][Discuss] 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的子集的

BZOJ 4408 神秘数

题解同各神犇的方法... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 using namespace std; int n,a[maxn],b[maxn],m,l,r,len,tot=0,regis; int ls[maxn*20],rs[maxn*20],sum[maxn*20],root[maxn]; void

BZOJ 3930 【CQOI2015】 选数

题目链接:选数 MDZZ,这种SB题我都Wa了这么多发,彻底没救系列- 首先,我们可以发现1,如果我们选了两个不同的数,那么它们的\(\gcd\)不会超过\(r-l+1\).于是,我们可以设一个\(f_i\)表示任取\(n\)个数,它们的\(\gcd\)为\(ik\)的方案数,最后我们要的答案就是\(f_1\).我们考虑容斥一下,在求\(f_i\)的时候,先把\([l,r]\)中是\(ik\)倍数的数全部拿出来,然后任意选\(n\)个,这样选出来的数他们的\(\gcd\)一定是\(ik\)的倍数

BZOJ 3385: [Usaco2004 Nov]Lake Counting 数池塘

题目 3385: [Usaco2004 Nov]Lake Counting 数池塘 Time Limit: 1 Sec  Memory Limit: 128 MB Description 农夫约翰的农场可以表示成N×M(1≤N,M≤100)个方格组成的矩形.由于近日的降雨, 在约翰农场上的不同地方形成了池塘.每一个方格或者有积水(’W’)或者没有积水(’.’).农夫约翰打算数出他的农场上共形成了多少池塘.一个池塘是一系列相连的有积水的方格,每一个方格周围的八个方格都被认为是与这个方格相连的. 现