WC模擬(1.14) T3 Try to find out the wrong in the test

Try to find out the wrong in the test

題目背景:

1.14 WC模擬T3

分析:線段樹優化DP + 複雜度分析

 

終於不用打公式了,心累······

首先我們只考慮d的限制,在滿足d限制的情況下,對於一個i,可行的上一個區間的端點,一定是一段連續的區間,並且,區間右端點是i,那麼我們只需要預處理出left[i]表示最小的可以用於更新i的位置,顯然left[i]是單增的,我們直接用一個單調隊列就可以維護了。

對於c限制並不是很好處理,於是我們考慮分治,對於一段區間[l, r],我們找出其中c值最大的位置p,遞歸處理[l, p - 1], [p, r],單獨處理最後一個區間包含p的情況。

首先比較顯然的是,如果我們要求最後一個轉移區間包含p,那麼可以從[l, p - 1]轉移的i,一定是屬於[max(p, l + c[p]), r]的,然後我們來分類討論一下。

1left[i] < li <= p - 1 + c

顯然滿足條件的i[l, i - c], 並且ii + 1的可行區間只相差一個i - c + 1這個位置的貢獻,那麼我們可以對於第一個位置在線段樹中查詢,然後後面的所有直接O(1)加上貢獻即可

2left[i] < li > p - 1 + c

顯然,滿足這個條件的i的可行轉移範圍全部都是[l, p - 1],那麼我們只需要二分出滿足這個條件的區間,然後查詢[l, p - 1]的答案,之後直接給可行區間打標記即可。

3l <= left[i] < p

這一段的left[i]都不能確定,所以只能直接在線段樹裏面查詢

4left[i] >= p

顯然無法轉移。
乍一看這不是n2logn的嗎,真的可能過?

現在我們來分析一下複雜度

首先,對於情況1,一定首先有一個log,接下來考慮會掃過多少數,顯然,滿足情況1的區間是[max(l + c, p), min(r, p + c - 1)],顯然區間長度是小於min(p - l + 1, r - p),相當於取被p分割的區間當中長度較小的一個。顯然前面的log,一共有n層,是nlogn,後面的區間長度可以通過類似於啓發式合併的思想分析,也是nlogn的。

對於情況2,顯然每層只有一個,所以是nlogn

對於情況3,我們可以發現,這種情況當且僅當,改點屬於區間的右邊部分,但是left[i],是在左邊部分,那麼顯然這種情況對於每一個點,有且僅會出現一次,所以是nlogn

所以,總的複雜度就是O(nlogn)的,當分治到l == r時,直接更新答案,然後更新到上層區間即可。

 

Source:

/*
	created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;	
	}
	for (x = 0; isdigit(c); c = read()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
		if (c == '-') iosig = true;	
	for (x = 0; isdigit(c); c = getchar()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 1000000 + 10;
const int mod = 1000000000 + 7;

int n;
int c[MAXN], d[MAXN], left[MAXN], f[MAXN], g[MAXN];

inline void add(int &x, int t) {
    x += t, (x >= mod) ? (x -= mod) : (0);
}

struct node {
    int c_id, f, g, tag_f, tag_g;
} tree[MAXN << 2 | 1];

inline void update(int &f, int &g, int cur_f, int cur_g) {
    if (cur_f > f) f = cur_f, g = cur_g;
    else if (f == cur_f) add(g, cur_g);
}

inline void update(int k) {
    node lc = tree[k << 1], rc = tree[k << 1 | 1];
    tree[k].c_id = ((c[lc.c_id] > c[rc.c_id]) ? lc.c_id : rc.c_id);
    if (lc.f > rc.f) tree[k].f = lc.f, tree[k].g = lc.g;
    else if (lc.f == rc.f) tree[k].f = lc.f, tree[k].g = (lc.g + rc.g) % mod;
    else tree[k].f = rc.f, tree[k].g = rc.g;
}

inline void modify(int k, int f, int g) {
    update(tree[k].f, tree[k].g, f, g);
    update(tree[k].tag_f, tree[k].tag_g, f, g);
}

inline void push_down(int k) {
    if (tree[k].tag_f > -1) {
        modify(k << 1, tree[k].tag_f, tree[k].tag_g);
        modify(k << 1 | 1, tree[k].tag_f, tree[k].tag_g);
        tree[k].tag_f = -1, tree[k].tag_g = 0;
    }
}

inline void build(int k, int l, int r) {
    tree[k].tag_f = -1, tree[k].tag_g = 0;
    if (l == r) {
        tree[k].c_id = l, tree[k].f = -1, tree[k].g = 0;
        return ;
    }
    int mid = l + r >> 1;
    build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
    update(k);
}

inline void modify(int k, int l, int r, int ql, int qr, int f, int g) {
    if (ql <= l && r <= qr) return modify(k, f, g);
    int mid = l + r >> 1;
    if (ql <= mid) modify(k << 1, l, mid, ql, qr, f, g);
    if (qr > mid) modify(k << 1 | 1, mid + 1, r, ql, qr, f, g);
}

inline void modify(int k, int l, int r, int pos, int f, int g) {
    if (l == r) return modify(k, f, g);
    int mid = l + r >> 1;
    push_down(k);
    if (pos <= mid) modify(k << 1, l, mid, pos, f, g);
    else modify(k << 1 | 1, mid + 1, r, pos, f, g);
}

inline void query(int k, int l, int r, int ql, int qr, int &f, int &g) {
    if (qr < ql) return; 
    if (ql <= l && r <= qr) return update(f, g, tree[k].f, tree[k].g);
    int mid = l + r >> 1;
    if (ql <= mid) query(k << 1, l, mid, ql, qr, f, g);
    if (qr > mid) query(k << 1 | 1, mid + 1, r, ql, qr, f, g);
}

inline void query(int k, int l, int r, int pos, int &f, int &g) {
    if (l == r) return update(f, g, tree[k].f, tree[k].g);
    int mid = l + r >> 1;
    if (pos <= mid) query(k << 1, l, mid, pos, f, g);
    else query(k << 1 | 1, mid + 1, r, pos, f, g);
    update(k);
}

inline int find(int k, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr) return tree[k].c_id;
    int mid = l + r >> 1;
    if (qr <= mid) return find(k << 1, l, mid, ql, qr);
    else if (ql > mid) return find(k << 1 | 1, mid + 1, r, ql, qr);
    else {
        int pos1 = find(k << 1, l, mid, ql, qr);
        int pos2 = find(k << 1 | 1, mid + 1, r, ql, qr);
        return (c[pos1] > c[pos2]) ? pos1 : pos2; 
    }
}

inline void read_in() {
    R(n);
    for (int i = 1; i <= n; ++i) R(c[i]), R(d[i]);
}

inline void pre_work() {
    int cur_pos = 0, head = 1, tail = 0;
    static int q[MAXN];
    for (int i = 1; i <= n; ++i) {
        while (head <= tail && d[q[tail]] >= d[i]) tail--;
        q[++tail] = i;
        int pos;
        while (head <= tail && q[head] <= cur_pos) head++;
        pos = d[q[head]];
        while (i - pos > cur_pos) {
            ++cur_pos;
            while (head <= tail && q[head] <= cur_pos) head++;
            pos = d[q[head]];
        }
        left[i] = cur_pos;
    }
    // for (int i = 1; i <= n; ++i) std::cout << left[i] << " ";
    // std::cout << '\n';
}

inline int binary(int x, int y, int val) {
    int l = x, r = y + 1;
    while (l + 1 < r) {
        int mid = l + r >> 1;
        (left[mid] < val) ? l = mid : r = mid;
    }
    // std::cout << "??" << l << '\n';
    return l;
}

inline void solve(int l, int r, int k) {
    int start = std::max(k, l + c[k]), end1 = std::min(r, k + c[k] - 1);
    int cur_f = -1, cur_g = 0, st = start;
    while (st <= end1) {
        if (left[st] >= l) break ;
        if (left[st] >= k) return ;
        if (st == start) query(1, 0, n, l, st - c[k], cur_f, cur_g);
        else update(cur_f, cur_g, f[st - c[k]], g[st - c[k]]);
        if (cur_f != -1) update(f[st], g[st], cur_f + 1, cur_g);
        ++st;
    }
    if (st > r) return ;
    if (left[st] < l) {
        int pos = binary(st, r, l);
        cur_f = -1, cur_g = 0;
        query(1, 0, n, l, k - 1, cur_f, cur_g);
        if (cur_f > -1) modify(1, 0, n, st, pos, cur_f + 1, cur_g);
        st = pos + 1;
    }
    while (st <= r) {
        if (left[st] >= k) return ;
        cur_f = -1, cur_g = 0;
        query(1, 0, n, left[st], std::min(k - 1, st - c[k]), cur_f, cur_g);
        if (cur_f > -1) update(f[st], g[st], cur_f + 1, cur_g);
        st++;
    }
}

inline void solve(int l, int r) {
    if (r < l) return ;
    if (l == r) {
        modify(1, 0, n, l, f[l], g[l]);
        f[l] = -1, g[l] = 0, query(1, 0, n, l, f[l], g[l]);
        return ;
    }
    int pos = find(1, 0, n, l + 1, r);
    solve(l, pos - 1), solve(l, r, pos), solve(pos, r);
}

int main() {
    freopen("schooldays.in", "r", stdin);
    freopen("schooldays.out", "w", stdout);
    read_in();
    pre_work();
    build(1, 0, n);
    for (int i = 1; i <= n; ++i) f[i] = -1;
    g[0] = 1, solve(0, n);
    // for (int i = 1; i <= n; ++i) std::cout << f[i] << " " << g[i] << '\n';
    if (f[n] > -1) std::cout << f[n] << " " << g[n];
    else std::cout << "-1";
    return 0;
}
發佈了221 篇原創文章 · 獲贊 27 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章