[CC FBR] Forbidden Sum

题意

  对多重数集 S 定义 Forbidden Sum F(S): 最小的无法凑出的自然数.

  即 $F(S) = \min_x [\not \exists T \subset S, ~s.t.~ \sum_{i \in T} i = x]$ .

  

  给定长度为 n 的数列 A .

  m 组询问 [l, r] , 求 F(A[l : r]) .

  n, m <= 100000 .

  1 <= a[i] <= 10 ^ 9 .

  1 <= a[1] + a[2] + ... + a[n] <= 10 ^ 9 .

分析

  我们先考虑如何求一个集合 S 的 F 值.

  探究 Forbidden Sum 的性质, 以更好的解决问题.

  对于一个数集 S ,  F(S) = x , 考虑 F( S + {w} ) 怎么求.

  我们可以多凑出 w, w+1, w+2, ..., w+x .

  若 w <= x+1 , 那么 F( S + {w} ) = F(S) + w , 反之不变.

  那么, 我们可以将 S 中的值 b[1], b[2], ..., b[m] 从小到大进行排序.

  从小到大逐个尝试添加, 直到添加失败.

  b[1] <= sum[0] + 1

  b[2] <= sum[1] + 1

  b[3] <= sum[2] + 1

  ...

  b[x] <= sum[x-1] + 1

  b[x+1] > sum[x] + 1

  那么 F(S) = sum[x] + 1 .

  修改一下这个算法.

  对于 sum[x] + 1 , 我们每次找到最大的 i , x < i <= n, 使得 b[i] <= sum[x] + 1 , 然后令 x = i 进行迭代.

  发现这样我们就可以二分查找最大的 i , 同时查找的次数是 log W .

  考虑在序列 A 中进行询问.

  我们只需要用 可持久化线段树 执行上述算法即可.

  时间复杂度为 O(n log n log W) .

  实现的时候只用查询值在 [lastsum + 1, sum] 中的和, 如果和为 0 , 那么就找不到, 否则令 lastsum = sum, sum += D .

  初始 lastsum = 0, sum = 1 .

实现

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 6
 7 namespace Input {
 8     const int S = 2000000;
 9     char s[S], *h = s+S, *t = h;
10     inline char getchr(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; }
11     inline int rd(void) {
12         int f = 1; char c = getchr(); for (; !isdigit(c); c = getchr()) if (c == ‘-‘) f = -1;
13         int x = 0; for (; isdigit(c); c = getchr()) x = x*10+c-‘0‘; return x*f;
14     }
15 }
16 using Input::rd;
17
18 const int N = 100005;
19 const int R = (int)1e9;
20 const int S = 5000000;        // n * log(1e9)
21
22 #define LC (c[x][0])
23 #define RC (c[x][1])
24 #define M ((L + R) >> 1)
25
26 int n, tot, rt[N];
27 int c[S][2], sum[S];
28
29 inline int Insert(int f, int L, int R, int w) {
30     int x = ++tot; LC = c[f][0], RC = c[f][1], sum[x] = sum[f];
31     if (L == R) return sum[x] += w, x;
32     w <= M ? LC = Insert(c[f][0], L, M, w) : RC = Insert(c[f][1], M+1, R, w);
33     sum[x] = sum[LC] + sum[RC];
34     return x;
35 }
36
37 inline int Sum(int rootL, int rootR, int L, int R, int l, int r) {
38     if (l <= L && R <= r) return sum[rootR] - sum[rootL];
39     int res = 0;
40     if (l <= M) res += Sum(c[rootL][0], c[rootR][0], L, M, l, r);
41     if (M < r) res += Sum(c[rootL][1], c[rootR][1], M+1, R, l, r);
42     return res;
43 }
44
45 int Calc(int l, int r) {
46     int sum = 1, last = 0;
47     while (true) {
48         int D = Sum(rt[l-1], rt[r], 1, R, last + 1, sum);
49         if (!D) break;
50         last = sum, sum += D;
51     }
52     return sum;
53 }
54
55 int main(void) {
56     #ifndef ONLINE_JUDGE
57         freopen("xsy1175.in", "r", stdin);
58     #endif
59
60     n = rd();
61     F(i, 1, n) {
62         int x = rd();
63         rt[i] = Insert(rt[i-1], 1, R, x);
64     }
65
66     int m = rd();
67     F(i, 1, m) {
68         int l = rd(), r = rd();
69         printf("%d\n", Calc(l, r));
70     }
71
72     return 0;
73 }
时间: 2024-10-06 15:38:35

[CC FBR] Forbidden Sum的相关文章

函数基本概念

本文目录 一.函数的声明 二.多源文件开发 三.#include 在上一讲中,简单介绍了函数的定义和使用,只要你想完成一个新功能,首先想到的应该是定义一个新的函数来完成这个功能.这讲继续介绍函数的其他用法和注意事项. 回到顶部 一.函数的声明 1.在C语言中,函数的定义顺序是有讲究的:默认情况下,只有后面定义的函数才可以调用前面定义过的函数 1 int sum(int a, int b) { 2 return a + b; 3 } 4 5 int main() 6 { 7 int c = sum

hdu 4925 Apple Tree

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4925 思路:直接计算坐标和,如果为奇数就种树,但要注意行或列为1的情况. 写啦两种代码:一种直接判断计算的,另一种优化计算的 code1: #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> using namespace std; int main() { int T;

【零基础学习iOS开发】【02-C语言】11-函数的声明和定义

在上一讲中,简单介绍了函数的定义和使用,只要你想完成一个新功能,首先想到的应该是定义一个新的函数来完成这个功能.这讲继续介绍函数的其他用法和注意事项. 一.函数的声明 1.在C语言中,函数的定义顺序是有讲究的:默认情况下,只有后面定义的函数才可以调用前面定义过的函数 1 int sum(int a, int b) { 2 return a + b; 3 } 4 5 int main() 6 { 7 int c = sum(1, 4); 8 return 0; 9 } 第5行定义的main函数调用

Guangsoushensou 2

<span style="color:#330099;">/* C - 广搜 基础 Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Submit Status Description A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the

Water --- CSU 1550: Simple String

Simple String Problem's Link:   http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1550 Mean: 略. analyse: 水题. Time complexity: O(n) Source code:  // Memory Time // 1347K 0MS // by : crazyacking // 2015-03-29-12.08 #include<map> #include<queue> #

树上启发式合并 (dsu on tree)

这个故事告诉我们,在做一个辣鸡出题人的比赛之前,最好先看看他发明了什么新姿势= =居然直接出了道裸题 参考链接: http://codeforces.com/blog/entry/44351(原文) http://blog.csdn.net/QAQ__QAQ/article/details/53455462 这种技巧可以在O(nlogn)的时间内解决绝大多数的无修改子树询问问题. 例1 子树颜色统计 有一棵n个点的有根树,根为1,每个点有一个1~n的颜色,对于每一个点给了一个数k,要询问这个子树

codeforces B - Preparing Olympiad(dfs或者状态压缩枚举)

B. Preparing Olympiad You have n problems. You have estimated the difficulty of the i-th one as integer ci. Now you want to prepare a problemset for a contest, using some of the problems you've made. A problemset for the contest must consist of at le

目标检测之显著区域检测---国外的一个图像显著区域检测代码及其效果图 saliency region detection

先看几张效果图吧 效果图: 可以直接测试的代码: 头文件: // Saliency.h: interface for the Saliency class.//////////////////////////////////////////////////////////////////////////===========================================================================// Copyright (c) 2009 R

Mysql源码目录结构

Programs for handling SQL commands. The "core" of MySQL. These are the .c and .cc files in the sql directory: derror.cc --- read language-dependent message file des_key_file.cc --- load DES keys from plaintext file discover.cc --- Functions for