17. [HAOI2011]problem a
阿新 • • 發佈:2022-04-07
最小化說謊的人數,就相當於最大化說真話的人數。如果一個人說有 \(a\) 個人分數比他高,\(b\) 個人分數比他低,顯然他的排名應當位於 \([a+1,n-b]\)。現在問題轉化為數軸上有若干個線段,問最多有多少條線段不相交。這可以用 dp 解決,\(dp[i]\) 表示到 \(i\) 為止最多不相交的線段個數,列舉在 \(i\) 處結尾的線段,從它起始位置的前一格處進行轉移。總複雜度 \(O(n\log n)\)。
#include <bits/stdc++.h> using namespace std; using pii = pair<int, int>; const int maxn = 1e5 + 5; map<pii, int> cnt; vector<int> seg[maxn]; int dp[maxn]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; for (int i = 1, l, r; i <= n; ++i) { cin >> l >> r; l++, r = n - r; if (r > l) continue; cnt[{l, r}]++; if (cnt[{l, r}] == 1) seg[r].push_back(l); } for (int i = 1; i <= n; ++i) { dp[i] = dp[i - 1]; for (auto &&l : seg[i]) { dp[i] = max(dp[i], dp[l - 1] + min(i - l + 1, cnt[{l, i}])); } } cout << n - dp[n] << endl; return 0; }