题解:P12543 嘟嘟嘟
wukaichen888 · · 题解
将直线按一二象限分类,
考虑最终应该构造一些十字对(两条直线相垂直)。
注意到十字对对于其他直线贡献固定,猜想一堆十字对带至多一条直线最优。
所以考虑两两一组归于坐标轴,形成十字对。
若一象限线严格多于二象限线,则将一象限线最靠近
二象限线严格多于一象限线,同理。
若一象限线、二象限线数量相等,将二象限线最靠近
显然一象限线、二象限线最多各剩一条。
然后变成
证明能量不减:可以考虑移动单条直线,贡献提高的线的数量多于贡献减少的线的数量,多直线同理。
这是
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e6+5,inf=1e18,mod=1e9+7;
ll l1,r1,l2,r2,d;
struct node{ll x,id;}b[N];
void rotate(std::vector<int>t,int x);
inline bool cmp(node u,node v){return u.x<v.x;}
void energy(int n,std::vector<int>v){
for(int i=0;i<n;i++) b[i+1]=node{v[i],i};
sort(b+1,b+n+1,cmp);
l1=1,r2=n;r1=0;
for(int i=1;i<=n;i++) if(b[i].x<25000) r1=i;
l2=r1+1;
while((l1<r1)||(l2<r2)){
if((r1-l1)>(r2-l2)){
// case1
rotate({b[l1].id},0-b[l1].x);
rotate({b[r1].id},25000-b[r1].x);
l1++,r1--;
}
else if((r1-l1)<(r2-l2)){
// case2
rotate({b[l2].id},25000-b[l2].x);
rotate({b[r2].id},50000-b[r2].x);
l2++,r2--;
}
else{
// case3
d=min(b[l2].x-25000,b[l1].x-0);
rotate({b[l1].id,b[l2].id},-d);
if(b[l2].x-25000>=b[l1].x-0) rotate({b[l2].id},-(b[l2].x-25000-d));
else rotate({b[l1].id},-(b[l1].x-0-d));
l1++,l2++;
}
}
if((l1==r1)&&(l2==r2)){
// case3
d=min(b[l2].x-25000,b[l1].x-0);
rotate({b[l1].id,b[l2].id},-d);
if(b[l2].x-25000>=b[l1].x-0) rotate({b[l2].id},-(b[l2].x-25000-d));
else rotate({b[l1].id},-(b[l1].x-0-d));
l1++,l2++;
}
}