ARC147C Min Diff Sum

Sol:

很妙的一道题。

将限制转化为线段讨论。

首先考虑一个特殊情况:当所有线段都相交的时候,答案显然为 \(0\).

那么假如有两条线段没有相交呢?

我们可以将是否相交的判定转化为 \(l_{max}\)\(r_{min}\) 的大小关系。

  • \(l_{max} \le r_{min}\) : 答案为 \(0\).

  • \(l_{max} > r_{min}\) : 这个时候我们考虑分解成子问题,并递归解决。此时 \(l_{max}\) 所处的线段肯定与 \(r_{min}\) 不同,将这两条线段 \(i, j\) 的贡献拉出来单独计算,并递归计算剩下的线段贡献。

    观察这两条线段与其他线段间产生的贡献:$\sum_{x \ne i, x\ne j}{|a_i - a_x| + |a_j - a_x|} + |a_i - a_j| $

    最小化前面的柿子,当 \(a_x\) 取到 \([r_j, l_i]\) 中间某值时贡献肯定最小,这个时候通过画图可以发现:所有 \(a_x\) 都可以取到 \([r_j, l_i]\) 间,于是产生的贡献为 \((V + 1) \times |a_i - a_j|\)\(V\) 为剩下的线段数),那么显然 \(a_i = l_i, a_j = r_j\) 时贡献最小。

前面的递归处理也不需要了,只需要排序后一个循环即可。

code:

#include<bits/stdc++.h>
#define int long long 
using namespace std;

const int N = 1e6 + 10;
int n, l[N], r[N];

bool cmp(int x, int y){return x > y;}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n; int ans = 0;
	for(int i = 1; i <= n; i++) cin >> l[i] >> r[i];
	sort(l + 1, l + n + 1, cmp); sort(r + 1, r + n + 1);
	for(int i = 1; i <= n; i++) ans += max(0ll, l[i] - r[i]) * (n - 2 * i + 1);
	cout << ans;
	
	return 0;
} 
posted @ 2024-04-24 13:09  Little_corn  阅读(6)  评论(0编辑  收藏  举报