博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 4408: [Fjoi 2016]神秘数
阅读量:5032 次
发布时间:2019-06-12

本文共 3526 字,大约阅读时间需要 11 分钟。

4408: [Fjoi 2016]神秘数

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 464  Solved: 281
[][][]

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

[ ][ ][ ]

 

福建自古出神题……

 

如果存在一个集合,使得$[1,x]$内的数字都能被表示,新加入一个数$y$,那么会出现如下两种情况:

  1. $y \leq x+1$,则新集合可以表示$[1,x+y]$内的所有数字。

  2. $y \gt x+1$,则新集合表示的区间会产生“断裂”,即$x+1$依旧无法被表示,所以该集合的神秘数还是$x+1$。

 

基于以上分析,产生下面的算法,用以求一个给定集合的神秘数:

首先设$ans=1$,作为最初假象的神秘数,然后求出

\[get=\sum_{a_{i} \leq ans}a_{i}\]

那么如果$get \lt ans$,则$ans$就是神秘数,否则令$ans=get+1$,继续过程。

 

那么用可持久化线段树维护区间内权值范围和即可。

 

1 #include 
2 3 inline char Char(void) 4 { 5 static const int siz = 1 << 10; 6 7 static char buf[siz]; 8 static char *hd = buf + siz; 9 static char *tl = buf + siz; 10 11 if (hd == tl) 12 fread(hd = buf, 1, siz, stdin); 13 14 return *hd++; 15 } 16 17 inline int Int(void) 18 { 19 int ret = 0, neg = 0, c = Char(); 20 21 for (; c < 48; c = Char()) 22 if (c == '-')neg ^= true; 23 24 for (; c > 47; c = Char()) 25 ret = ret * 10 + c - '0'; 26 27 return neg ? -ret : ret; 28 } 29 30 const int mxn = 100005; 31 const int siz = 5000005; 32 33 int n, m, num[mxn], map[mxn], tot; 34 35 int ls[siz], rs[siz], sm[siz], cnt, root[mxn]; 36 37 void insert(int &t, int f, int l, int r, int p, int v) 38 { 39 t = ++cnt; 40 41 ls[t] = ls[f]; 42 rs[t] = rs[f]; 43 sm[t] = sm[f] + v; 44 45 if (l != r) 46 { 47 int mid = (l + r) >> 1; 48 49 if (p <= mid) 50 insert(ls[t], ls[f], l, mid, p, v); 51 else 52 insert(rs[t], rs[f], mid + 1, r, p, v); 53 } 54 } 55 56 int query(int a, int b, int l, int r, int lt, int rt) 57 { 58 if (l == lt && r == rt) 59 return sm[a] - sm[b]; 60 61 int mid = (l + r) >> 1; 62 63 if (rt <= mid) 64 return query(ls[a], ls[b], l, mid, lt, rt); 65 else if (lt > mid) 66 return query(rs[a], rs[b], mid + 1, r, lt, rt); 67 else 68 return query(ls[a], ls[b], l, mid, lt, mid) + query(rs[a], rs[b], mid + 1, r, mid + 1, rt); 69 } 70 71 signed main(void) 72 { 73 n = Int(); 74 75 for (int i = 1; i <= n; ++i) 76 num[i] = map[i] = Int(); 77 78 std::sort(map + 1, map + n + 1); 79 80 tot = std::unique(map + 1, map + n + 1) - map; 81 82 for (int i = 1; i <= n; ++i) 83 num[i] = std::lower_bound(map + 1, map + tot, num[i]) - map, 84 insert(root[i], root[i - 1], 1, tot, num[i], map[num[i]]); 85 86 m = Int(); 87 88 for (int i = 1; i <= m; ++i) 89 { 90 int l = Int(); 91 int r = Int(); 92 93 int ans = 1, get, pos; 94 95 while (true) 96 { 97 pos = std::upper_bound(map + 1, map + tot, ans) - map - 1; 98 get = query(root[r], root[l - 1], 1, tot, 1, pos); 99 if (get < ans)break;100 else ans = get + 1;101 }102 103 printf("%d\n", ans);104 }105 }

 

@Author: YouSiki

 

转载于:https://www.cnblogs.com/yousiki/p/6277420.html

你可能感兴趣的文章
【转】VS2012编译出来的程序,在XP上运行,出现“.exe 不是有效的 win32 应用程序” “not a valid win32 application”...
查看>>
函数中关于const关键字使用的注意事项
查看>>
js随机数的取整
查看>>
用php做一个简单的注册用户功能
查看>>
一款基于css3的3D图片翻页切换特效
查看>>
Feign使用Hystrix无效原因及解决方法
查看>>
hadoop2.2.0_hbase0.96_zookeeper3.4.5全分布式安装文档下载
查看>>
Flutter 贝塞尔曲线切割
查看>>
golang 的编译安装以及supervisord部署
查看>>
阿里架构师,讲述基于微服务的软件架构模式
查看>>
Eclipse导入maven项目时,Pom.xml文件报错处理方法
查看>>
01、JAVA开发准备
查看>>
txmpp
查看>>
【Github教程】史上最全github使用方法:github入门到精通
查看>>
抽象工厂模式(Abstract Factory)
查看>>
luogu1373 小a和uim之大逃离 (dp)
查看>>
Redis的Pub/Sub客户端实现
查看>>
springMVC入门(一)------springMVC基本概念与安装
查看>>
Sam做题记录
查看>>
[bzoj] 2453 维护数列 || 单点修改分块
查看>>