专栏文章
题解:P12543 嘟嘟嘟
P12543题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mip97nyo
- 此快照首次捕获于
- 2025/12/03 08:13 3 个月前
- 此快照最后确认于
- 2025/12/03 08:13 3 个月前
将直线按一二象限分类, 归一象限, 归二象限。
考虑最终应该构造一些十字对(两条直线相垂直)。
注意到十字对对于其他直线贡献固定,猜想一堆十字对带至多一条直线最优。
所以考虑两两一组归于坐标轴,形成十字对。
若一象限线严格多于二象限线,则将一象限线最靠近 轴的两条直线一条一条移动到坐标轴。
二象限线严格多于一象限线,同理。
若一象限线、二象限线数量相等,将二象限线最靠近 的 、一象限线最靠近 的 。两条一起旋转, 往 方向转, 往 方向转,使离目标坐标轴近的移动至坐标轴,再一步操作另一条移动至坐标轴。
显然一象限线、二象限线最多各剩一条。
然后变成 按最后一种做就行, 不用管。
证明能量不减:可以考虑移动单条直线,贡献提高的线的数量多于贡献减少的线的数量,多直线同理。
这是 次操作,移动至多 条线的解法。
CPP#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++;
}
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...