题目大意
有一个长度为 L(L≤109) L ( L ≤ 10 9 ) 的环形铁路,在铁路的某些点上有一些人或一些办公室,现在要求给每个人配一个办公室,让所有人的上班路程最短。
思路
考虑问题的简化版:如果不是环形,是一条直线铁路那么很明显应该是贪心:就像括号匹配一样将人和办公室匹配即可。
回到这个问题,我们应该断环为链。
下面来证明为什么环一定可以被断开:想想一下一个人-办公室的配对关系,若环无法被断开,则一定有任意几个人的路线有交叉并包含了整个环,那么我们一定可以重新排列这几个人,把环去掉。
考虑朴素做法:枚举断点,每次做一次“括号匹配”,复杂度
O(n2)
O
(
n
2
)
,T
考虑这个答案的被计算过程:每两个点之间的线段被覆盖了若干次,次数为人
+1
+
1
办公室
−1
−
1
赋权后的
|tot|∗len
|
t
o
t
|
∗
l
e
n
考虑断点若向右移动,会产生什么样的影响:有些线段的覆盖次数会少1,有些会多1。断点移动相当于将最开头的一个人/办公室移动到最后。若是人移动到最后,所有线段的覆盖次数+1,若是办公室移动到最后,所有线段的覆盖次数-1。利用这个性质,先随意断开,之后慢慢往后推即可。
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<map>
#include<vector>
#include<ctime>
#include<stack>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define ll long long
#define ull unsigned long long
using namespace std;
inline ll read()
{
long long f=1,sum=0;
char c=getchar();
while (c<'0' || c>'9')
{
if (c=='-') f=-1;
c=getchar();
}
while (c>='0' && c<='9')
{
sum=sum*10+c-'0';
c=getchar();
}
return sum*f;
}
const int MAXN=100010;
struct node{
int pos,opt,id;
node () {}
node (int pos,int opt,int id):pos(pos),opt(opt),id(id) {}
};
node v[MAXN];
int a[MAXN],b[MAXN];
int seg[MAXN],t[MAXN],num,cnt;
int x[MAXN];
int main()
{
int n,L;
scanf("%d%d",&n,&L);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),num++,v[num]=node(a[i],1,i);
for (int i=1;i<=n;i++)
scanf("%d",&b[i]),num++,v[num]=node(b[i],-1,i);
sort(v+1,v+1+num,[](node i,node j){return i.pos<j.pos;});
v[num+1]=v[1],v[num+1].pos+=L;
ll tot=0,sum=0;
int opt=0;
for (int i=1;i<=num;i++)
{
opt+=v[i].opt;
seg[++cnt]=v[i+1].pos-v[i].pos;
sum+=seg[cnt];
t[cnt]=opt;
tot+=(ll)seg[cnt]*t[cnt];
}
for (int i=1;i<=cnt;i++)
x[i]=i;
sort(x+1,x+1+cnt,[](int i,int j){return t[i]<t[j];});
ll len=0,last=0,ans=1e18,pos;
for (int i=1;i<=cnt;i++)
{
tot+=len*(t[x[i]]-last)-(sum-len)*(t[x[i]]-last);
if (tot<ans) ans=tot,pos=x[i];
last=t[x[i]];
len+=seg[x[i]];
}
cout<<ans<<endl;
stack <node> s;
int now=pos+1;
tot=0;
while (tot<n)
{
if (now>num) now=1;
if (v[now].opt==1)
{
if (s.empty() || s.top().opt==1) s.push(v[now++]);
else x[v[now++].id]=s.top().id,s.pop(),tot++;
}
else
{
if (s.empty() || s.top().opt==-1) s.push(v[now++]);
else x[s.top().id]=v[now++].id,s.pop(),tot++;
}
}
for (int i=1;i<=n;i++)
printf("%d ",x[i]);
return 0;
}