codeforces 1214F

题目链接

题意

有一个长度为m的环形铁路,在铁路的某些点上有一些人或一些办公室,现在要求给每个人配一个办公室,让所有人的上班路程最短。人和办公室的数量都是n。

数据范围

m 1 e 9 , n 2 e 5 m\le 1e9,n\le 2e5

解法

参考博文

首先可以发现,如果不是环,而是一条链,那么一定是将人和办公室分别排序,然后一一对应,因为如果不是这样,就一定会花费更多的路程.

然后如果是环,那么首先可以想到的是枚举某个位置,断开环,然后一一对应地匹配.
具体来讲求的是 m i n d = 0 n 1 i = 1 n d i s t ( a i , b i + d ) min^{n-1}_{d=0} {\sum_{i=1}^{n}{dist(a_i,b_{i+d})}}
这样的复杂度是 O ( n 2 ) O(n^2)

然后考虑优化这个过程
设r=l+d,那么其实贡献有几种对应关系
a l b r , b r a l a l b r + m a_l\le b_r,b_r-a_l\le a_l-b_r+m ,对答案的贡献为 ( a l ) + ( b r ) (-a_l)+(b_r)
a l b r , b r a l > a l b r + m a_l\le b_r,b_r-a_l > a_l-b_r+m ,对答案的贡献为 ( a l + m ) + ( b r ) (-a_l+m)+(b_r)
a l > b r , a l b r a l b r + m a_l> b_r,a_l-b_r\le a_l-b_r+m ,对答案的贡献为 ( a l ) ( b r ) (a_l)-(b_r)
a l > b r , a l b r > a l b r + m a_l> b_r,a_l-b_r> a_l-b_r+m ,对答案的贡献为 ( a l ) + ( b r + m ) (-a_l)+(b_r+m)
然后这些贡献可以转化成对于a,b两个数组各自的贡献,然后我们就可以对于一个 a i a_i ,分别二分出4种 b i b_i 的区间,然后分别将对应的贡献记录进答案数组.然后对 b b 做同样的事.
由于是许多区间修改,所以这个答案数组可以用一个差分数组维护,表示如果选择在第i个位置断开,那么答案是多少,复杂度是 O ( n l o g n ) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=4e5+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int m,n;
typedef pair<int,int> pii;
#define fst first
#define scd second
pii a[maxn],b[maxn];
int t1[maxn],t2[maxn],tt1[maxn],tt2[maxn],c[maxn],ans[maxn];
void update(int l,int r,int d){
	c[l]+=d;c[r+1]-=d;
}
void modify(int l,int r,int d){
	//printf("%lld %lld %lld\n",l,r,d);
	if(l>r)return ;
	l=((l+n)%n+n)%n,r=((r+n)%n+n)%n;
	if(l>r){update(l,n-1,d);update(0,r,d);}
	else update(l,r,d);
}
signed main(){
	m=read(),n=read();
	for(int i=1;i<=n;i++)a[i].fst=read(),a[i].scd=i;;
	for(int i=1;i<=n;i++)b[i].fst=read(),b[i].scd=i;
	sort(a+1,a+1+n);sort(b+1,b+1+n);
	for(int i=1;i<=n;i++){
		t1[i]=a[i].first;tt1[i]=t1[i]<<1;
		t2[i]=b[i].first;tt2[i]=t2[i]<<1;
	}
	for(int i=1;i<=n;i++){
		int l=1,r=upper_bound(tt2+1,tt2+1+n,tt1[i]-m-1)-tt2-1;
		modify(l-i,r-i,-t1[i]);
		l=r+1,r=upper_bound(tt2+1,tt2+1+n,tt1[i]-1)-tt2-1;
		modify(l-i,r-i,t1[i]);
		l=r+1,r=upper_bound(tt2+1,tt2+1+n,tt1[i]+m)-tt2-1;
		modify(l-i,r-i,-t1[i]);
		l=r+1,r=n;
		modify(l-i,r-i,t1[i]+m);
	}
	for(int i=1;i<=n;i++){
		int l=1,r=upper_bound(tt1+1,tt1+1+n,tt2[i]-m-1)-tt1-1;
		modify(i-r,i-l,-t2[i]);
		l=r+1,r=upper_bound(tt1+1,tt1+1+n,tt2[i])-tt1-1;
		modify(i-r,i-l,t2[i]);
		l=r+1,r=upper_bound(tt1+1,tt1+1+n,tt2[i]+m)-tt1-1;
		modify(i-r,i-l,-t2[i]);
		l=r+1,r=n;
		modify(i-r,i-l,t2[i]+m);
	}
	int pos=0;
	for(int i=1;i<n;i++)
	c[i]+=c[i-1],pos=(c[i]<c[pos])?i:pos;
	//for(int i=0;i<n;i++)printf("%lld ",c[i]);
	printf("%lld\n",c[pos]);
	for(int i=1,j=pos+1;i<=n;i++,j=(j==n)?1:j+1)ans[a[i].scd]=b[j].scd;
	for(int i=1;i<=n;i++)printf("%lld ",ans[i]);
	return 0;
}

发布了62 篇原创文章 · 获赞 1 · 访问量 980

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103895191
今日推荐