1. 程式人生 > 其它 >AtCoder Beginner Contest 217 D~E

AtCoder Beginner Contest 217 D~E

比賽連結:Here

ABC水題,

D - Cutting Woods

題意:開始一根木棒長度為 \(n\) 並以 \(1\) 為單位在木棒上標記\((1\sim n)\) ,輸出 \(q\) 次操作

  • 操作 \(1\) 斷開 \(x\) 所在的木棒:\([1,n]\)\(x\) 斷開變成了 \([1,x],[x + 1,n]\)
  • 操作 \(2\) 查詢 \(x\) 所在區間的長度

資料範圍:\(n\le 10^{9},q\le 1e5,1\le x\le 1e9\)

題解:

一開始沒有想到這個性質所以卡住了,

在分割之後左邊以及右邊這個區間的答案是固定的,也就是說答案只跟分割點有關,比如區間 \([l,r]\)

分割 \(x\)​ 變成了 \([l,x],[x+1,r]\)

可以發現可以發現
\(l\)\(x\) 這個區間的詢問答案都是 \(x−l+1\)
\(x+1\)\(r\) 這個區間的詢問答案都是 \(r−l+1\)

所以可以考慮二分找到所在區間相鄰 \(2\) 個的分割點下標

先考慮邊界問題

邊界無非是:\(0\sim n + 1,0\sim n,1\sim n,1\sim n +1\)\(4\)​ 種的其中一種

這個時候先假設區間是 \([1,2],[3,4],[5]\)

分割點是 0/1 2 4 5/5+1

對於查詢2
找到第一個大於等於2的數是2
第一個小於2的數應該是 0/1
答案是2
所以應該是 2 - 0 = 2
左邊界應該是0

在考慮查詢5
答案是1
找到第一個大於等於5的數是5/6
第一個小於5的數應該是4
所以應該是 5 - 4 = 1
右邊界是n

在考慮二分操作的時候 分割點陣列保持有序
所以可以用set動態維護

時間複雜度:\(\mathcal{O}(Nlog N)\)

set<int>s;
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    s.insert(0);
    s.insert(n);
    while (m--) {
        int c, x;
        cin >> c >> x;
        if (c == 1) s.insert(x);
        else
            cout << *s.lower_bound(x) - *--s.upper_bound(x) << "\n";
        	// 因為沒 -- 調了半天
    }
}

E - Sorting Queries

題意:給出一個空的序列和 \(q\) 次操作

  • 操作 \(1\):​ 在序列末尾新增一個數 \(x\)
  • 操作 \(2\) :輸出序列第一個數
  • 操作 \(3\):給當前序列排序

資料範圍:\(q\le 1e5,1\le x\le 1e9\)

題解:

假設不考慮操作 \(3\),那麼我們可直接模擬,

但在操作 \(3\)的影響下,需要維護排序對佇列的影響,

假設佇列中兩個元素,\(head,fail\) 對應隊頭和隊尾

暴力時間複雜度是 \(\mathcal{O}(n^2 logn)\) 肯定是不可取的

在排序的時候我們可以考慮邊插入邊排序,用 \(set\)​ 維護

然後把對頭指向 \(set\) 後面的第一個下標

這樣時間複雜度便降到了 \(\mathcal{O}(n logn)\)

const int N = 1e6 + 10;
ll a[N];
multiset<ll>s;
bool st[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int head = 0, fail = 0;
    int t; cin >> t;
    int k = 1; // k = 1 表示佇列第一個數的下標是1
    while (t--) {
        int op; cin >> op;
        if (op == 1) {
            int x; cin >> x;
            a[++fail] = x;
        } else if (op == 2) {
            // 如果排序過
            if (s.size()) {
                cout << *s.begin() << "\n" ;
                s.erase(s.begin());
            } else {
                cout << a[k] << "\n";
                st[k] = 1;
                k += 1;
            }
        } else {
            for (int i = k ; i <= fail ; i ++) {
                if (!st[i]) s.insert(a[i]) ;
            }
            // 插入之後 對頭指向隊尾的下一個下標
            k = fail + 1 ;
        }
    }
}

The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。