一道好冷门的好题啊,算是对于一个小结论数据结构的一点考验吧

首先看完题目我们发现要从这个神秘数的性质入手,我们观察or手玩可得:

  1. 如果有\(x\)个\(1\),那么\([1,x]\)都是可以表示出来的
  2. 如果我此时加入的数\(y>x\),那么这个数无法被表示,因此便为答案
  3. 如果我此时加入的数\(y\le x\),那么这个数可以被表示,并且可以表示的区间变成了\([1,x+y]\)

重复以上过程,肯定可以得出答案

但这样对于每一次询问都要进行一次排序,时间复杂度为\(O(nm\ logn)\),肯定跑不过去的。我们换一种想法,假设我此时已经表示出了\([1,x]\),那么我统计一下在区间\([l,r]\)中所有小于等于\(x+1\)的数的和\(s\)

若\(s\ge x+1\),说明此时必定还存在更大的组合方案,于是可以表示的区间变为\([1,s]\)

再考虑上述的核心过程:统计一段区间内小于等于某个数的数的和

直接主席树即可,把值域线段树的点权改为数的和即可,查询的时候还是分左右子树查找

由于查询之后每次的答案扩大至少一倍,因此总复杂度\(O(m\ log^2n)\)

CODE

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N=100005;
  6. struct President_tree
  7. {
  8. int ch[2],sum;
  9. }node[N*20];
  10. int n,m,q,rt[N],a[N],b[N],tot,l,r;
  11. inline char tc(void)
  12. {
  13. static char fl[100000],*A=fl,*B=fl;
  14. return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
  15. }
  16. inline void read(int &x)
  17. {
  18. x=0; char ch; while (!isdigit(ch=tc()));
  19. while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
  20. }
  21. inline void write(int x)
  22. {
  23. if (x>9) write(x/10);
  24. putchar(x%10+'0');
  25. }
  26. inline int find(int x)
  27. {
  28. int l=1,r=m,mid,res;
  29. while (l<=r)
  30. {
  31. mid=l+r>>1;
  32. if (b[mid]<=x) res=mid,l=mid+1; else r=mid-1;
  33. }
  34. return res;
  35. }
  36. inline void build(int &now,int l,int r)
  37. {
  38. if (!now) now=++tot; if (l==r) return; int mid=l+r>>1;
  39. build(node[now].ch[0],l,mid); build(node[now].ch[1],mid+1,r);
  40. }
  41. inline int insert(int lst,int l,int r,int id,int x)
  42. {
  43. int now=++tot; node[now]=node[lst]; node[now].sum+=x;
  44. if (l==r) return now; int mid=l+r>>1;
  45. if (id<=mid) node[now].ch[0]=insert(node[lst].ch[0],l,mid,id,x);
  46. else node[now].ch[1]=insert(node[lst].ch[1],mid+1,r,id,x); return now;
  47. }
  48. inline int query(int lst,int now,int l,int r,int beg,int end)
  49. {
  50. int mid=l+r>>1,res=0;
  51. if (l>=beg&&r<=end) return node[now].sum-node[lst].sum;
  52. if (beg<=mid) res+=query(node[lst].ch[0],node[now].ch[0],l,mid,beg,end);
  53. if (end>mid) res+=query(node[lst].ch[1],node[now].ch[1],mid+1,r,beg,end);
  54. return res;
  55. }
  56. int main()
  57. {
  58. //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
  59. register int i; read(n);
  60. for (i=1;i<=n;++i)
  61. read(a[i]),b[i]=a[i]; read(q);
  62. sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1; build(rt[0],1,m);
  63. for (i=1;i<=n;++i)
  64. {
  65. int x=find(a[i]);
  66. rt[i]=insert(rt[i-1],1,m,x,a[i]);
  67. }
  68. for (i=1;i<=q;++i)
  69. {
  70. read(l); read(r); int ans=1;
  71. for (;;)
  72. {
  73. int x=find(ans),s=query(rt[l-1],rt[r],1,m,1,x);
  74. if (s>=ans) ans=s+1; else break;
  75. }
  76. write(ans); putchar('\n');
  77. }
  78. return 0;
  79. }

Luogu P4587 [FJOI2016]神秘数的更多相关文章

  1. LUOGU P4587 [FJOI2016]神秘数(主席树)

    传送门 解题思路 如果区间内没有\(1\),那么答案就为\(1\),从这一点继续归纳.如果区间内有\(x\)个\(1\),设区间内\([2,x+1]\)的和为\(sum\),如果\(sum=0\),那 ...

  2. 洛谷 P4587 [FJOI2016]神秘数

    大鸽子 llmmkk 正在补8.3号咕掉的题 时隔两个月,再看到这道题,我又是一脸懵,这种思维的培养太重要了 链接: P4587 题意: 给出 \(n\) 个点的序列,\(m\) 次询问区间神秘数. ...

  3. 洛谷P4587 [FJOI2016]神秘数(主席树)

    题面 洛谷 题解 考虑暴力,对于询问中的一段区间\([l,r]\),我们先将其中的数升序排序,假设当前可以表示出\([1,k]\)目前处理\(a_i\),假如\(a_i>k+1\),则答案就是\ ...

  4. P4587 [FJOI2016]神秘数(主席树)

    题意:给出1e5个数 查询l,r区间内第一个不能被表示的数 比如1,2,4可以用子集的和表示出[1,7] 所以第一个不能被表示的是8 题解:先考虑暴力的做法 把这个区间内的数字按从小到大排序后 从前往 ...

  5. 220722 T4 求和 /P4587 [FJOI2016]神秘数 (主席树)

    好久没打主席树了,都忘了怎么用了...... 假设我们选了一些数能构成[0,x]范围内的所有值,下一个要加的数是k(k<=x+1),那么可以取到[0,x+k]内的所有取值,所以有一种做法: 对于 ...

  6. (bzoj4408)[FJOI2016]神秘数(可持久化线段树)

    (bzoj4408)[FJOI2016]神秘数(可持久化线段树) bzoj luogu 对于一个区间的数,排序之后从左到右每一个数扫 如果扫到某个数a时已经证明了前面的数能表示[1,x],那么分情况: ...

  7. 【BZOJ4408】[FJOI2016]神秘数(主席树)

    [BZOJ4408][FJOI2016]神秘数(主席树) 题面 BZOJ 洛谷 题解 考虑只有一次询问. 我们把所有数排个序,假设当前可以表示出的最大数是\(x\). 起始\(x=0\). 依次考虑接 ...

  8. 【LG4587】[FJOI2016]神秘数

    [LG4587][FJOI2016]神秘数 题面 洛谷 题解 首先我们想一想暴力怎么做 对于一段区间\([l,r]\) 我们先将它之间的数升序排序 从左往右扫, 设当前我们可以表示出的数为\([1,x ...

  9. BZOJ4299 & CC FRBSUM:ForbiddenSum & BZOJ4408 & 洛谷4587 & LOJ2174:[FJOI2016]神秘数——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4299 https://www.lydsy.com/JudgeOnline/problem.php? ...

随机推荐

  1. 盐城 - 开设IT公司的好地方

    盐城:位于江苏省北部,这一好像只能算三线的城市,不久前当选为“国家中心城市”.在全国仅有的50城市中名列34.它可成为发展IT产业的好地方. (1)人才济济.从这里走出去的高级人才数不胜数,留在这里的 ...

  2. 根据学习廖雪峰老师的git教程做的笔记

    根据学习廖雪峰老师的git教程做的笔记 安装git 进行git的配置 配置您的用户名和邮箱地址,使用--global 这个参数表明了在此台机器上的所有仓库都会使用该配置 $ git config -- ...

  3. mysqlreport工具

    进行MySQL的配置优化,首先必须找出MySQL的性能瓶颈所在:而SHOW STATUS输出的报告正是用来计算性能瓶颈的参考数据.mysqlreport不像SHOW STATUS那样简单的罗列数据,而 ...

  4. 阿里云上安装pip3(Ubuntu)

    安装pip3: 这个简单啊,到网上下载get-pip.py的脚本,然后scp到你的阿里云服务器上,python3 get-pip.py即可. 如果不会scp,哈哈,按照下面的几步: wget http ...

  5. SSO阅读有感

    SSO比较详细且理解.赞 链接:https://www.cnblogs.com/ywlaker/p/6113927.html

  6. vSphere ESXi 重新安装后的虚拟机恢复(转载)

    安装的 ESXi 的物理主机密码忘记,登录 不上了,需要重新安装 ESXi,安装后恢复原先物理主机上的 虚拟机的方法如下(VMFS分区完好): 关于 VMFS 分区: ESXi 的安装时会划分一个分区 ...

  7. 【16】有关python面向对象编程

    面向对象编程 一.第一个案例---创建类 #__author:"吉" #date: 2018/10/27 0027 #function: # 设计类: ''' 1 类名:首字母大写 ...

  8. java集合类List

    1.List Vector:线程安全的. ArrayList:适合查找与顺序添加. LinkedList:适合随机插入与删除. 1.1ArrayList与LinkedList的add添加 1.1.1A ...

  9. python五十七课——正则表达式(边界字符)

    演示匹配锚字符(边界字符)^:从字符串头部开始匹配,在开启多行模式下(re.M),可以尝试匹配每一行的头部数据$:从字符串尾部开始匹配,在开启多行模式下(re.M),可以尝试匹配每一行的尾部数据A:从 ...

  10. sphinx笔记

    sphinx笔记 下载中文版coreseek包 1:解压后,将etc下的mysql.conf文件复制一份放到上级目录下,改名为sphinx.conf 2:配置文件: 2.1:source配置数据源 s ...