POJ1201 Intervals 差分約束(貪心也可)
阿新 • • 發佈:2020-09-04
題面
給定 n 個區間 [ai,bi]和 n 個整數 ci。
你需要構造一個整數集合 Z,使得∀i∈[1,n],Z 中滿足ai≤x≤bi的整數 x 不少於 ci 個。
求這樣的整數集合 Z 最少包含多少個數。
輸入格式
第一行包含整數 n。
接下來n行,每行包含三個整數ai,bi,ci。
輸出格式
輸出一個整數表示結果。
資料範圍
1≤n≤50000,
0≤ai,bi≤50000,
1≤ci≤bi−ai+1
輸入樣例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
輸出樣例:
6
題解
差分約束
一堆不等式, 明顯是差分約束
設 s[i], 表示 0~i 區間選擇了 s[i] 個數
則 s[b] - s[a - 1] >= c
只是這樣的話, 不能將 -1(a >= 0, a - 1 >= -1)~5e4 每個節點連線起來
我們發現 s[i] - s[i - 1] >= 0, s[i - 1] - s[i] >= -1
這樣就將所有節點全部連線起來, 由於解的存在, 無負環,
對於差分約束, 要麼把所有點扔進佇列, 要麼選擇一個初始節點
對於這道題要麼把, 0~50000全扔進去, 要麼從 -1, s[-1] ≡ 0
由於越界, 我們將 -1 由 5e4 + 1代替, 或者整體將區間右移, 變為 0~50001
const int N = 5e4 + 5; const double eps = 1e-6; int n, m, _, k; int h[N], ne[N << 2], to[N << 2], co[N << 2], tot; int a[N], b[N], c[N], dis[N]; bool v[N]; void add(int u, int v, int c) { ne[++tot] = h[u]; co[h[u] = tot] = c; to[tot] = v; } void spfa(int s) { queue<int> q; memset(dis, -1, sizeof dis); q.push(s); dis[s] = 0; while (!q.empty()) { int x = q.front(); q.pop(); v[x] = 0; for (int i = h[x]; i; i = ne[i]) { int y = to[i]; if (dis[y] >= dis[x] + co[i]) continue; dis[y] = dis[x] + co[i]; if (!v[y]) q.push(y), v[y] = 1; } } } int main() { sc(n); rep(i, 1, 5e4) add(i - 1, i, 0), add(i, i - 1, -1); add(5e4 + 1, 0, 0); add(0, 5e4 + 1, -1); rep(i, 1, n) { sc(a[i]), sc(b[i]), sc(c[i]); --a[i]; if (a[i] == -1) a[i] = 5e4 + 1; add(a[i], b[i], c[i]); } spfa(5e4 + 1); pr(dis[50000]); return 0; }
貪心
將b按照升序排列, 儘量將數字靠近 b 放置, 加上樹狀陣列,並查集優化, 即可
const int N = 5e4 + 5; const double eps = 1e-6; int n, m, _, k; int c[N], f[N]; pair<PII, int> p[N]; void add(int x, int k) { for (; x <= 5e4; x += -x & x) c[x] += k; } int ask(int x) { int ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; } int find(int x) { if (x == f[x]) return x; return f[x] = find(f[x]); } int main() { sc(n); rep(i, 1, n) sc(p[i].fi.se), sc(p[i].fi.fi), sc(p[i].se); rep(i, 1, 5e4 + 1) f[i] = i; sort(p + 1, p + 1 + n); rep(i, 1, n) { int x = p[i].fi.se + 1, y = p[i].fi.fi + 1, cnt = p[i].se; cnt -= ask(y) - ask(x - 1); if (cnt <= 0) continue; for (int j = find(y); cnt; j = f[j]) --cnt, add(j, 1), f[j] = find(j - 1), ++m; } pr(m); return 0; }