SGU 313 Circular Railway

题目链接

题目大意

有一个长度为 L ( L 10 9 ) 的环形铁路,在铁路的某些点上有一些人或一些办公室,现在要求给每个人配一个办公室,让所有人的上班路程最短。

思路

考虑问题的简化版:如果不是环形,是一条直线铁路那么很明显应该是贪心:就像括号匹配一样将人和办公室匹配即可。
回到这个问题,我们应该断环为链。
下面来证明为什么环一定可以被断开:想想一下一个人-办公室的配对关系,若环无法被断开,则一定有任意几个人的路线有交叉并包含了整个环,那么我们一定可以重新排列这几个人,把环去掉。
考虑朴素做法:枚举断点,每次做一次“括号匹配”,复杂度 O ( n 2 ) ,T
考虑这个答案的被计算过程:每两个点之间的线段被覆盖了若干次,次数为人 + 1 办公室 1 赋权后的 | 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;
}

猜你喜欢

转载自blog.csdn.net/szh_0808/article/details/80914512
sgu