题意
给你 n
块石头的坐标 (x[i],y[i])
,可以对任意一块石头交换横纵左边,代价为 w[i]
,求最小的代价使得 Max(x[i]-x[j])+Max(y[i]-y[j])
最小。
Solution:
首先考虑当什么时候取到最小值。
结论:当所有石子都在 y=x
一侧时最优。
证明:首先考虑 n=2
的情况,对于任意 i
满足 x[i]<y[i]
。此时 Max(x[i]-x[j])+Max(y[i]-y[j])
最小。对于 n+1
的情况,假设前面是这样的:那么取 x[n+1]<y[n+1]
使得答案最小。证毕。
考虑最小化花费。首先 内部的点不能翻
,只能让答案变大。
那么现在有四种情况,对于每种情况,可以贪心 O(n)
判断每个点是否翻转。
实际上我们可以把四种情况放到一个矩形里,也就是说用左上角那个矩形就够了。(说明一下,我这里探究出来有 6
种情况,不过 2,3
种和 1,4
种似乎是同一个矩形)。
时间复杂度 O(n)
。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define PII pair<ll,ll>
using namespace std;
const int mx=1e6+5;
int n;
PII one,two;
PII ans;
struct node{
int x,y,w,op;
}q[mx];
//期望得分 80~100 pts
void check(int x,int x2,int y,int y2) {
ll res=0;
for(int i=1;i<=n;i++) {
if(x<=q[i].x&&q[i].x<=x2&&y<=q[i].y&&q[i].y<=y2) continue;
if(x<=q[i].y&&q[i].y<=x2&&y<=q[i].x&&q[i].x<=y2) res+=q[i].w;
else return;
}
if(res<ans.second) {
ans.second=res;
for(int i=1;i<=n;i++) {
if(x<=q[i].x&&q[i].x<=x2&&y<=q[i].y&&q[i].y<=y2) q[i].op=0;
else q[i].op=1;
}
}
}
void solve() {
int x(INF),y(INF),x2(0),y2(0);
for(int i=1;i<=n;i++) {
scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].w);
if(q[i].x>q[i].y) {
swap(q[i].x,q[i].y);
q[i].op=1;
}
x=min(x,q[i].x);
x2=max(x2,q[i].x);
y=min(y,q[i].y);
y2=max(y2,q[i].y);
if(q[i].op) {
swap(q[i].x,q[i].y);
q[i].op=0;
}
}
ans.first=1ll*(x2-x)*2+(y2-y)*2;
check(x,x2,y,y2);
check(x,y2,y,x2);
check(y,y2,x,x2);
check(y,x2,x,y2);
}
int main() {
scanf("%d",&n); ans=make_pair(INF,INF);
solve();
printf("%lld %lld\n",ans.first,ans.second);
for(int i=1;i<=n;i++) printf("%d",q[i].op);
}