P4587 [FJOI2016] 神秘数
题目描述
一个可重复数字集合 \(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\),\(m\) 次询问,每次询问包含两个参数 \(l,r\),你需要求出由 \(a_l,a_{l+1},\cdots,a_r\) 所组成的可重集合的神秘数。
对于 \(100\%\) 的数据点,\(1\le n,m\le {10}^5\),\(\sum a\le {10}^9\)。
题目解析
先考虑单组询问,\(l=1, r=n\) 的做法。
将 \(a\) 数组从小到大排序,设遍历到一个数 \(a_i\) 时,前面的数可以表示出 \([1, x]\) 中的所有数,那么:
- 若 \(a_i \le x + 1\),则任何 \([a_i + 1, a_i + x]\) 中的数都可以被表示为 \(a_i + u\) 的形式,其中 \(u \in [1, x]\). 于是新的可表示区间变为 \([1, a_i + x]\);
- 若 \(a_i > x + 1\),则 \(x+1\) 无法被表示,寄。
时间复杂度 \(O(n)\).
考虑优化。假设当前表示出了 \([1, x]\) 中的所有数,那么下一步放进 \([1, x+1]\) 中的任何数都一定是合法的。于是依次放入所有先前还未放入的 \(\le x + 1\) 的数,新的可表示区间为 \([1, x + sum]\).
注意到 \(x+sum\) 其实就是 \([1, x + 1]\) 中所有数的和,于是用线段树维护这个和即可。
这个操作很类似斐波那契数列的累加,再乘上线段树的复杂度,大概为 \(\log \sum a_i \cdot \log n\).
加上数都要在 \([l, r]\) 中的限制,就把线段树换成主席树即可,每次相当于在第 \(l \sim r\) 个版本之间查询。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], root[N], lc[N << 5], rc[N << 5], idx, sum[N << 5], m, l, r;
int update(int l, int r, int p, int x)
{
int y = ++idx;
lc[y] = lc[x], rc[y] = rc[x], sum[y] = sum[x] + p;
if(l == r) return y;
int mid = (l + r) >> 1;
if(p <= mid) lc[y] = update(l, mid, p, lc[y]);
if(mid < p) rc[y] = update(mid + 1, r, p, rc[y]);
return y;
}
int query(int l, int r, int L, int R, int x, int y)
{
if(l > r || L > R) return 0;
if(L <= l && r <= R) return sum[y] - sum[x];
int mid = (l + r) >> 1, res = 0;
if(L <= mid) res += query(l, mid, L, R, lc[x], lc[y]);
if(mid < R) res += query(mid + 1, r, L, R, rc[x], rc[y]);
return res;
}
int main()
{
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++)
root[i] = update(1, 1e9, a[i], root[i - 1]);
cin >> m;
while(m--)
{
cin >> l >> r;
int x = 0;
while(1)
{
int c = query(1, 1e9, 1, x + 1, root[l - 1], root[r]);
if(c > x) x = c;
else break;
}
cout << x + 1 << '\n';
}
return 0;
}

浙公网安备 33010602011771号