1. 程式人生 > >【LG4587】[FJOI2016]神秘數

【LG4587】[FJOI2016]神秘數

digi .org 兩種 ring inline getchar() ostream git 之間

【LG4587】[FJOI2016]神秘數

題面

洛谷

題解

首先我們想一想暴力怎麽做
對於一段區間\([l,r]\)
我們先將它之間的數升序排序
從左往右掃,
設當前我們可以表示出的數為\([1,x]\),待插入的數為\(a_i\)
會有下面兩種情況:
1.\(a_i> x+1\)時,\(x+1\)肯定表示不出來\(ans=x+1\)
2.\(a_i\leq x+1\)時,值域變為\([1,x+a_i]\),繼續掃
那麽我們暴力的復雜度為\(O(nmlogn)\)
考慮怎麽優化這個過程
還是用剛才的思路
設當前值域\([1,x]\)
\(ans=x+1\)
若小於等於\(ans\)的數的和\(res\geq ans\)

,則一定有未選的且小於等於\(ans\)的數,
\(ans=res+1\)即可。
反之說明答案就是\(ans\),直接\(break\)
因為有\(\sum a_i\leq 10^9\),用主席樹維護
所以復雜度\(O(m(logn)(log\sum a_i))\)
代碼

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std; 
inline int gi() { 
    register int data = 0, w = 1; 
    register char ch = 0; 
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
    return w * data; 
}
const int MAX_N = 1e5 + 5; 
const int INF = 1e9; 
struct Node { int ls, rs, v; } t[MAX_N << 5]; 
int rt[MAX_N], tot = 0; 
void insert(int &o, int p, int l, int r, int pos, int v) { 
    o = ++tot, t[o] = t[p], t[o].v += v; 
    if (l == r) return ; 
    int mid = (l + r) >> 1; 
    if (pos <= mid) insert(t[o].ls, t[p].ls, l, mid, pos, v); 
    else insert(t[o].rs, t[p].rs, mid + 1, r, pos, v); 
} 
int query(int v, int u, int l, int r, int ql, int qr) { 
    if (ql <= l && r <= qr) return t[u].v - t[v].v; 
    int mid = (l + r) >> 1, res = 0; 
    if (ql <= mid) res += query(t[v].ls, t[u].ls, l, mid, ql, qr); 
    if (qr > mid) res += query(t[v].rs, t[u].rs, mid + 1, r, ql, qr); 
    return res; 
} 
int N, a[MAX_N]; 
int main () { 
    N = gi(); for (int i = 1; i <= N; i++) a[i] = gi(); 
    for (int i = 1; i <= N; i++) insert(rt[i], rt[i - 1], 1, INF, a[i], a[i]); 
    int M = gi();
    while (M--) { 
        int l = gi(), r = gi(), ans = 1; 
        for (;;) { 
            int res = query(rt[l - 1], rt[r], 1, INF, 1, ans); 
            if (res >= ans) ans = res + 1; 
            else break; 
        } 
        printf("%d\n", ans); 
    } 
    return 0; 
} 

【LG4587】[FJOI2016]神秘數