bzoj5397 circular 隨機化(

題目大意ios

給定一個環,環上有一些線段,試選出最多的線段算法


題解優化

提醒:這多是一篇很是歡樂的題解spa

咱們考慮倍長環,而後斷環爲鏈code

咱們考慮枚舉開頭的線段,而後作一次貪心get

這樣子的複雜度根據實現的不一樣是\(O(n^2 \log n)\)或者\(O(n^2)\)string

不妨假設咱們不知道倍增能優化,咱們考慮答案的構成,記答案爲\(B\)it

若是\(B < \sqrt n\),那麼咱們只須要每次跳\(B\)次就能夠出解io

若是\(B > \sqrt n\),那麼咱們隨機取\(\frac{n}{B}\)個線段做爲端點,而後取最優值class

這樣子,咱們就獲得了一個看起來徹底不對勁的\(O(n \sqrt n)\)的算法

可是人都是懶惰的,咱們考慮直接用第二種方法

通過實踐,實際上只要取\(2\)個線段做爲端點就足夠\(A\)掉本題了

複雜度\(O(n \log n)\),雖然正確性徹底沒法保證呢

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

#define gc getchar
inline int read() {
    int p = 0, w = 1; char c = gc();
    while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
    while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
    return p * w; 
}

const int sid = 2e5 + 5;

int n, m, tot;
int L[sid], R[sid];

struct seg {
    int l, r;
    seg() {}
    seg(int _l, int _r) : l(_l), r(_r) {}
    friend bool operator < (seg a, seg b)
    { return a.r > b.r; }
} A[sid];
priority_queue <seg> q;

inline int solve(int o) {
    int ret = 0, nr = -1;
    rep(i, 1, tot) 
        if(A[i].l >= L[o] && A[i].r <= L[o] + m) q.push(A[i]);
    while(!q.empty()) {
        seg B = q.top(); q.pop();
        if(B.l < nr) continue; 
        nr = max(nr, B.r); ret ++;
    } 
    return ret;
}

int main() {
    m = read(); n = read();
    rep(i, 1, n) {
        int l = read(), r = read();
        L[i] = l; R[i] = r;
        if(l > r) A[++ tot] = seg(l, r + m);
        else {
            A[++ tot] = seg(l, r);
            A[++ tot] = seg(l + m, r + m);
        }
    }
    int ans = 0, k = 2;
    for(ri i = 1; i <= n; i += n / k) ans = max(ans, solve(i));
    printf("%d\n", ans);
    return 0;
}
相關文章
相關標籤/搜索