Codechef FRBSUM 解题报告
题目思路中比较难的一点是一个结论:如果使用集合S的子集可以构造出[0,s]的所有数字, 那么设S集合之外全集之内存在一个数字x,那么若把数字x加入到集合S中,则可以构造出[x,s+x]的全部数字。 若存在的最小x > 1, 则 s+1为不可构造解。
这个题目基本上是基于上面的这个结论来解决的。结论比较容易证明。 对于任何一个可能的数组, 0 都是一个必定可以构造的值, 所以从0开始, 不断判断在当前的[0, s]的构造存在的情况下, s+1是否可以构造即可。
写代码时候遇到了坑。 由于 a[i] <= 1e9, 所以我无脑离散化了一下, 于是TLE了。 看别人的解题报告后发现, 不离散化AC。
代码如下:
1 #include<bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define lson l,m 5 #define rson m+1,r 6 typedef long long ll; 7 using namespace std; 8 const int maxn = 1e5+10; 9 const int maxv = 1e9; 10 const int maxtree = maxn*32; 11 int a[maxn], Hash[maxn], n; 12 int T[maxn], val[maxtree], L[maxtree], R[maxtree], tot; 13 14 int build(int l, int r){ 15 int rt = ++tot; 16 val[rt] = 0; 17 if(l < r){ 18 int m = (l+r)/2; 19 L[rt] = build(lson); 20 R[rt] = build(rson); 21 } 22 return rt; 23 } 24 25 int update(int pre, int p, int v, int l, int r){ 26 int rt = ++tot; 27 L[rt] = L[pre], R[rt] = R[pre]; 28 val[rt] = val[pre] + v; 29 if(l < r){ 30 int m = (l+r)/2; 31 if(p <= m) L[rt] = update(L[pre], p, v, lson); 32 else R[rt] = update(R[pre], p, v, rson); 33 } 34 return rt; 35 } 36 37 int query(int srt, int trt, int begin, int end, int l, int r){ 38 if(begin <= l && r <= end) return val[trt] - val[srt]; 39 int m = (l+r)/2, res = 0; 40 if(begin <= m) res += query(L[srt], L[trt], begin, end, lson); 41 if(end > m) res += query(R[srt], R[trt], begin, end, rson); 42 return res; 43 } 44 45 int main() { 46 int m, l, r; 47 scanf("%d", &n); 48 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 49 for(int i = 1; i <= n; i++) T[i] = update(T[i-1], a[i], a[i], 1, maxv); 50 scanf("%d", &m); 51 while(m--){ 52 scanf("%d%d", &l, &r); 53 int _mx = 0; 54 for(int i = 1; ; i = _mx + 1){ 55 _mx = query(T[l-1], T[r], 1, i, 1, maxv); 56 if(_mx < i){ 57 printf("%d\n", i); 58 break; 59 } 60 } 61 } 62 }