zoukankan      html  css  js  c++  java
  • Bzoj 4408: [Fjoi 2016]神秘数 可持久化线段树,神题

    4408: [Fjoi 2016]神秘数

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 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的子集的和,故集合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

    Source

    鸣谢yyh上传

    题解:

    FJ神题!!!

    这道题实在是迷幻。。。

    根本想不到啊!!!QAQ!!!我一直在想数学方法。。。

    看了题解,竟然是可持久化线段树!!!!(Orz 出题人)

    好了不废话了。。。

    先把序列从小到大排序。

    假设当前神秘数为ans,则[1,ans-1]一定能用S集合中的数表示。然后如果当前加入一个数字a,则可以分为两类讨论。

    1,若a<=ans,则当前可以将区间变长为:[1,ans+a-1]  ,然后神秘数变为ans+a。

    2,若a>ans,则区间中有空,ans不变。

    然后ans从1开始,每次求小于ans的数的和get,ans变为get+1。

    这里用可持久化线段树维护即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define MAXN 100010
     4 int sum[40*MAXN],a[MAXN],root[MAXN],SIZE;
     5 struct node
     6 {
     7     int left,right;
     8 }tree[40*MAXN];
     9 int read()
    10 {
    11     int s=0,fh=1;char ch=getchar();
    12     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
    13     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
    14     return s*fh;
    15 }
    16 void Add(int x,int &y,int l,int r,int add)
    17 {
    18     y=++SIZE;
    19     sum[y]=sum[x]+add;
    20     if(l==r)return;
    21     tree[y].left=tree[x].left;tree[y].right=tree[x].right;
    22     int mid=(l+r)/2;
    23     if(add<=mid)Add(tree[x].left,tree[y].left,l,mid,add);
    24     else Add(tree[x].right,tree[y].right,mid+1,r,add);
    25 }
    26 int query(int x,int y,int l,int r,int k)
    27 {
    28     if(l==r)return sum[y]-sum[x];
    29     int mid=(l+r)/2;
    30     if(k<=mid)return query(tree[x].left,tree[y].left,l,mid,k);
    31     else return query(tree[x].right,tree[y].right,mid+1,r,k)+sum[tree[y].left]-sum[tree[x].left];
    32 }
    33 int main()
    34 {
    35     int n,tot,i,m,l,r,ans,get;
    36     n=read();
    37     tot=0;
    38     for(i=1;i<=n;i++)a[i]=read(),tot+=a[i];
    39     SIZE=0;
    40     for(i=1;i<=n;i++)Add(root[i-1],root[i],1,tot,a[i]);
    41     m=read();
    42     for(i=1;i<=m;i++)
    43     {
    44         l=read();r=read();
    45         ans=1;
    46         while(1)
    47         {
    48             get=query(root[l-1],root[r],1,tot,ans);
    49             if(get<ans)break;
    50             ans=get+1;
    51         }
    52         printf("%d
    ",ans);
    53     }
    54     return 0;
    55 }
  • 相关阅读:
    jvm2-垃圾回收
    Elasticsearch脑裂问题详细分析以及解决方案
    ThreadLocal原理(基于jdk1.8)
    seata-分布式事务-学习笔记
    Java中的数组
    HAProxy 详细配置说明
    (基础)--- 约数
    (基础)--- Trie树
    Oracle 数据类型对比 不同数据类型对数据空间占用及查询效率影响
    python F score打分
  • 原文地址:https://www.cnblogs.com/Var123/p/5311491.html
Copyright © 2011-2022 走看看