• BZOJ4408: [Fjoi 2016]神秘数


    $n leq 100000$个正整数,$m leq 100000$个询问,每次问区间$[L,R]$不在这几个数组成的可重集合的子集数字和的集合的最小正整数,说人话就是这几个数瞎选加起来不能凑成的最小正整数。

    以为是数学题。。没想到是一主席树。。

    可以考察集合里加入一个数之后对集合不能凑成的数的影响。假设原先集合最小不能凑成的数为$x$,加入了一个$y$,如果$y>x$那没意义,如果$y<=x$,相当于把一个背包移动$y$位后和原来的或起来,那么1到$x+y-1$都可以取到,答案至少应该是$x+y$(可能原来就能取到这个数,所以答案会更大但不会更小);再判断是不是答案时,需要考察$leq x+y$的所有数字。

    由于$x->x+y$是由“$x$是原来的答案,且$ leq x$的数的和超过了$x$”,那可不可以得出这样的结论:$x$从1开始验证,原答案是$x$时,$leq x$的数的和$sum$超过了$x$,那么$1$到$sum$的数字都是能得到的!

    证明:当$x=1$时显然。当$x>1$时,假设上一个验证的答案是$y$。如果比$x$小的数加起来补到$x$那$x$就得不到;如果加起来超过$x$,由于$leq y$的数加起来到了$x-1$,因此一定有一些数字$>y$。把能得到的数放在一个背包里,一个$>y$而$leq x$的数$a$会把这个背包移动$a$位然后或起来,由于这个数$leq x$,而原来背包$1$到$x-1$都是已经可达的,因此这样的一次移动+取或不会在$1$到$x+z-1$之间造成空隙,因此每个数在背包里移动+取或后,能取到$1$到$x-1+这些>y而leq x$的数且不留空隙。

    那复杂度呢?最坏的情况下,$y->x$之后每次增添一个数$y+1$,这样可构造数列$1,2,3,5,8,13……$这数列有点熟??所以复杂度是约等于$logMax$的,每次需要对一个区间找小于等于某个数的数的和,上主席树。复杂度$m*log_2n*log_2Max$。

     1 //#include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 //#include<time.h>
     6 //#include<complex>
     7 #include<algorithm>
     8 #include<stdlib.h>
     9 using namespace std;
    10 
    11 int n,m;
    12 #define maxn 100011
    13 int root[maxn];
    14 int a[maxn],lisa[maxn],li=0;
    15 struct SMT
    16 {
    17     struct Node
    18     {
    19         int ls,rs;
    20         int sum;
    21     }a[maxn*20];
    22     int size,n;
    23     void clear(int m) {size=0; a[0].sum=0; n=m;}
    24     void insert(int &x,int y,int L,int R,int pos)
    25     {
    26         x=++size; a[x].sum=a[y].sum+lisa[pos];
    27         if (L==R) {a[x].ls=a[x].rs=0; return;}
    28         int mid=(L+R)>>1;
    29         if (pos<=mid) insert(a[x].ls,a[y].ls,L,mid,pos),a[x].rs=a[y].rs;
    30         else insert(a[x].rs,a[y].rs,mid+1,R,pos),a[x].ls=a[y].ls;
    31     }
    32     void insert(int &x,int y,int pos) {insert(x,y,1,n,pos);}
    33     int query(int x,int y,int v)
    34     {
    35         v=upper_bound(lisa+1,lisa+1+li,v)-lisa;
    36         if (v==li+1) return a[y].sum-a[x].sum;
    37         int ans=0,L=1,R=n;
    38         while (L<R)
    39         {
    40             int mid=(L+R)>>1;
    41             if (v<=mid) x=a[x].ls,y=a[y].ls,R=mid;
    42             else ans+=a[a[y].ls].sum-a[a[x].ls].sum,x=a[x].rs,y=a[y].rs,L=mid+1;
    43         }
    44         return ans;
    45     }
    46 }t;
    47 
    48 int main()
    49 {
    50     scanf("%d",&n);
    51     for (int i=1;i<=n;i++) scanf("%d",&a[i]),lisa[++li]=a[i];
    52     sort(lisa+1,lisa+1+n); li=unique(lisa+1,lisa+1+li)-lisa-1; t.clear(li);
    53     for (int i=1;i<=n;i++) a[i]=lower_bound(lisa+1,lisa+1+li,a[i])-lisa,t.insert(root[i],root[i-1],a[i]);
    54     scanf("%d",&m);
    55     while (m--)
    56     {
    57         int x,y; scanf("%d%d",&x,&y);
    58         int ans=1,tmp;
    59         while ((tmp=t.query(root[x-1],root[y],ans))>=ans) ans=tmp+1;
    60         printf("%d
    ",ans);
    61     }
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    一行命令搞定node.js 版本升级
    doesn't contain a valid partition table 解决方法
    debian kill 进程等命令
    FastDFS配置说明(中英文)
    FastDFS问题汇总
    FastDFS常见命令
    FastDFS安装配置手册
    windows 与Linux 互传文件
    FtpClient中文乱码问题解决
    windows 配置host
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8566512.html
Copyright © 2020-2023  润新知