前言
題目連結:洛谷。
題意簡述
你需要構造一個 \(1 \sim n\) 的排列 \(a\),滿足 \(m\) 個條件,格式如下:
-
1 x y v
:\(\max \limits _ {i = l} ^ r a_i = v\)。 -
2 x y v
:\(\min \limits _ {i = l} ^ r a_i = v\)。
題目分析
首先這個最值很難受,考慮能不能轉化成我們喜歡的二元關係。比如,當 \([l, r]\) 的最值為 \(v\) 時,說明 \(v\) 必須出現在這段區間內。再思考一下,對於最大值,為了保證這段區間的最大值是 \(v\),那麼大於 \(v\) 的數就不能出現在這段區間內,最小值同理。把前者“必須出現”轉化為補集的“不能出現”,這樣我們處理出了對於每一個值 \(v\) 不能出現的位置。
有什麼用呢?我在膜尼賽上用爆搜騙分。直接騙肯定不好看,這時候就需要一些常見的剪枝最佳化。對於限制類題目,我們把限制多的先搜尋能節約不少時間。此外,尋找到一個沒有確定的位置可以使用雙向連結串列最佳化。預處理區間覆蓋轉化為差分。能夠得到 \(86\) 分的好成績。
話說回來,這麼搜肯定是錯的,那還有什麼做法呢?我們必須敏感地注意到位置和值的特殊二元關係。到了最後,每一個位置一定一一對應一個值,將“不能”反轉得到若干“可能”的匹配關係,最後的對應一定這些可能匹配中的一種。
不妨繼續抽象模型。有紅黃兩種顏色的小球各 \(n\) 個,我們知道了每一個紅球可能和哪些黃球匹配,找到一種匹配方式,使得紅黃球一一對應。這不就是二分圖的裸題了嗎?我們將可能得匹配方式看作是值向位置的連邊,最終的答案就是位置對應的那個值。
注意到存在無解的情況,此時說明二分圖不存在完美匹配,判斷即可。
時間複雜度理論上來說可以最佳化到:\(\Theta(m \log n + n^{\frac{5}{2}})\),但是可能比不過常數小的 \(\Theta(nm + n ^ 3)\)?
程式碼
#include <cstdio>
#define isdigit(x) ('0' <= x && x <= '9')
inline void read(int &x) {
x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar());
for (; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
}
const int N = 220;
int n, m, val[N], mi[N], mx[N], cant[N][N];
int to[N * N], nxt[N * N], head[N], tot;
int vis[N], timer, mark[N];
bool dfs(int now) {
for (int i = head[now]; i; i = nxt[i]) {
int to = ::to[i];
if (vis[to] != timer) {
vis[to] = timer;
if (!mark[to] || dfs(mark[to])) {
mark[to] = now;
return true;
}
}
}
return false;
}
signed main() {
read(n), read(m);
for (int i = 1; i <= n; ++i) mx[i] = n;
for (int i = 1, op, l, r, v; i <= m; ++i) {
read(op), read(l), read(r), read(v);
++cant[v][1], --cant[v][l];
++cant[v][r + 1], --cant[v][n + 1];
for (int j = l; j <= r; ++j) {
if (op == 1)
v < mx[j] && (mx[j] = v);
else
v > mi[j] && (mi[j] = v);
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cant[i][j] += cant[i][j - 1];
if (mi[j] <= i && i <= mx[j] && !cant[i][j]) {
to[++tot] = j;
nxt[tot] = head[i];
head[i] = tot;
}
}
}
for (int i = 1; i <= n; ++i) {
++timer;
if (!dfs(i)) return puts("-1"), 0;
}
for (int i = 1; i <= n; ++i) printf("%d ", mark[i]);
return 0;
}
總結 & 反思
說實話,都想到爆搜,想不到二分圖匹配確實不應該,應該歸根結底是二分圖模型不熟悉了。
二分圖是處理兩種不同型別的物件之間的對應關係。對於本題,一個排列的構造,我們如果能找出值和下標的二元關係,就能建立二分圖,跑匹配,最後輸出匹配的方案。