P10046 [CCPC 2023 北京市赛] 哈密顿
*P10046 [CCPC 2023 北京市赛] 哈密顿
问题等价于每个
绝对值太烦人了,先去掉,则答案为
考虑到每个
- 如果选出的匹配(钦定
a_i < b_j )存在a_i > b_j 的情况,其贡献为b_j - a_i ,只会将答案算小。 - 如果补充的匹配(钦定
a_i > b_j )存在a_i < b_j 的情况,其贡献为a_i - b_j ,只会将答案算小。 - 要让选出的匹配不成环,只需让选出的
a_i 下标集合A 和b_j 下标集合B 不完全相同。每次选A\backslash B 的某个i ,让它匹配A\cap B 的某个j ,然后从A 删去i ,从B 删去j ,则A\backslash B 大小不变且一定不会成环。假设u\to v 成环,那么v\in B 且v 之前作为某个i 出现,即当时v\in A ,则当时v\in A\cap B ,和v\in A\backslash B 矛盾。当A\cap B = \varnothing 时随便匹配就行。因为初始A\backslash B \neq \varnothing ,所以构造可行。
因此,我们的目标是在选中的两组下标集合不完全相同的限制下,最大化选出的
将
对
- 若
\Delta |A| = -1 ,则- 若
c_k \neq d_{n - k + 1} 或者|A| = 1 ,则将c_k 和d_{n - k + 1} 分别从A 和B 中删去。 - 否则删去
c_k 和d_{n - k + 2} ,或c_{k - 1} 和d_{n - k + 1} 。
- 若
- 若
\Delta |A| = 0 ,则将c_k 和d_{n - k + 1} 删去,换成c_k 和d_{n - k} ,或c_{k + 1} 和d_{n - k + 1} 。 - 若
\Delta |A| = 1 ,则- 若
c_{k + 1}\neq d_{n - k} 或|A| = n - 1 ,则加入c_{k + 1} 和d_{n - k} 。 - 否则加入
c_{k + 1} 和d_{n - k - 1} ,或c_{k + 2} 和d_{n - k} 。
- 若
正确性证明分两步,一步是证明给出的方案是在固定
时间复杂度为除排序外线性。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdi = pair<double, int>;
using pdd = pair<double, double>;
using ull = unsigned long long;
using LL = __int128_t;
#define ppc(x) __builtin_popcount(x)
#define clz(x) __builtin_clz(x)
bool Mbe;
// ---------- templates above ----------
constexpr int N = 1e5 + 5;
int n;
struct dat {
int val, id;
bool operator < (const dat &z) const {
return val < z.val;
}
} a[N], b[N];
void solve() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i].val >> b[i].val;
a[i].id = b[i].id = i;
}
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
int l = 0, r = n + 1;
map<int, int> mp;
ll ans = 0;
while(l < n) {
if(a[l + 1].val > b[r - 1].val) break;
mp[a[++l].id]++, mp[b[--r].id]--;
ans += b[r].val - a[l].val;
}
bool ok = 0;
for(pii it : mp) ok |= it.second > 0;
if(!ok && l < n && l) {
ll res = -1e18;
auto f = [&](int l, int r) {
return ll(b[r].val - a[l].val);
};
if(a[l].id != b[r].id || l == 1) res = max(res, -f(l, r));
else res = max(res, max(-f(l, r + 1), -f(l - 1, r)));
res = max(res, max(f(l, r - 1), f(l + 1, r)) - f(l, r));
if(a[l + 1].id != b[r + 1].id || l == n - 1) res = max(res, f(l + 1, r - 1));
else res = max(res, max(f(l + 2, r - 1), f(l + 1, r - 2)));
ans += res;
}
ans *= 2;
for(int i = 1; i <= n; i++) ans += a[i].val - b[i].val;
cout << ans << endl;
}
bool Med;
signed main() {
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#ifdef ALEX_WEI
FILE* IN = freopen("1.in", "r", stdin);
FILE* OUT = freopen("1.out", "w", stdout);
#endif
int T = 1;
while(T--) solve();
fprintf(stderr, "%.3lf ms\n", 1e3 * clock() / CLOCKS_PER_SEC);
return 0;
}
/*
g++ a.cpp -o a -std=c++14 -O2 -DALEX_WEI
*/