Loading

ISIJ 2021 Training Contest 1

链接:http://144.202.116.213/contest/4

A

略。

B

本来想尝试一下数位 dp 的非递归方法,结果写挂了,最后只好写的递归……

解法显然,略。

C

首先可以发现,我们只要确定了 \(A\) 中的前两个元素,后面的元素也都确定了:设 \(A_1=x,A_2=y\),那么因为 \(A\) 是“和谐”的,所以只能这样填:\(\{x,y,y-x,-x,-y,x-y,\dots\}\)

于是 \(\mathrm{dis}(A,B)=|x-B_1|+|y-B_2|+|y-x-B_3|+|-x-B_4|+|-y-B_5|+|x-y-B_6|+\dots\)。将 \(B_{6k+3},B_{6k+4},B_{6k+5}\) 变成相反数,那么就只需要考虑 \(\{x,y,x-y\}\) 的影响了。

考虑到 \(x\)\(y\) 中一定有至少一个会取 \(B\) 中的值。

枚举 \(x\)\(y\) 一定要取 \(\{B_{3k+2},x-B_{3k+3}\}\) 这些数的中位数。这个减号不太好处理,可以仿照上文相反数的处理方法,将它变成加号。

枚举 \(y\)\(x\) 一定要取 \(\{B_{3k+1},y+B_{3k+3}\}\) 这些数的中位数。

以枚举 \(y\) 为例:维护两个指针 \(p_1,p_2\) 表示 \(B_{3k+1}\) 中最接近中位数的位置、\(y+B_{3k+3}\) 中最接近中位数的位置。可以发现 在 \(y\) 单调递增的同时,\(p_1\) 是单调不减的、\(p_2\) 是单调不增的。

如果一个数 \(x\) 在数列 \(S\) 与它相等的范围是 \([l,r]\),那么当且仅当 \(l\le \lceil\dfrac{|S|}{2}\rceil\land r\ge \lceil\dfrac{|S|}{2}\rceil\) 时,它是中位数

两次枚举并维护。

代码
const int N=3e5+5;
int n,m[4],p[4][N];ll b[4][N],ps[4][N];
int L(int i,ll x){return lower_bound(b[i]+1,b[i]+m[i]+1,x)-b[i]-1;}
int Le(int i,ll x){return upper_bound(b[i]+1,b[i]+m[i]+1,x)-b[i]-1;}
int G(int i,ll x){return m[i]-Le(i,x);}
int Ge(int i,ll x){return m[i]-L(i,x);}
bool Valid1_(int i,int j,ll x,ll mid,int len){
	int l=L(i,mid)+L(j,mid-x);
	return l<(len+1)/2;
}
bool Valid2_(int i,int j,ll x,ll mid,int len){
	int r=Le(i,mid)+Le(j,mid-x);
	return r>=(len+1)/2;
}
ll Dist(int i,ll x,int l=-1){
	if(l==-1) l=L(i,x);
	return x*l-ps[i][l]+(ps[i][m[i]]-ps[i][l])-x*(m[i]-l);
}
int main(){
	Read(n);
	For(i,1,n){
		int j=(i-1)%3+1;
		scanf("%lld",&b[j][++m[j]]);p[j][m[j]]=i;
		if(i%6==4||i%6==5||i%6==0) b[j][m[j]]*=-1;
	}
	For(j,1,3) sort(b[j]+1,b[j]+m[j]+1);
	For(j,1,3) For(i,1,m[j]) ps[j][i]=ps[j][i-1]+b[j][i];
	ll ans=Inf;
	for(int i=1,mp1=1,mp2=m[3];i<=m[1];++i){
		ll x=b[1][i];ll res=Dist(1,x);
		while(mp1<=m[2]&&!Valid2_(2,3,x,b[2][mp1],m[2]+m[3])) ++mp1;
		while(mp2>=1&&!Valid1_(2,3,x,x+b[3][mp2],m[2]+m[3])) --mp2;
		if(mp1<=m[2]&&Valid1_(2,3,x,b[2][mp1],m[2]+m[3])){
			res+=Dist(2,b[2][mp1])+Dist(3,b[2][mp1]-x);
		}else if(mp2>=1&&Valid2_(2,3,x,x+b[3][mp2],m[2]+m[3])){
			res+=Dist(2,x+b[3][mp2])+Dist(3,b[3][mp2]);
		}else res=Inf;
		chkmin(ans,res);
	}
	For(j,1,3) For(i,1,m[j]){
		if(p[j][i]%6==3||p[j][i]%6==0) b[j][i]*=-1;
	}
	For(j,1,3) sort(b[j]+1,b[j]+m[j]+1);
	memset(ps,0,sizeof ps);
	For(j,1,3) For(i,1,m[j]) ps[j][i]=ps[j][i-1]+b[j][i];
	for(int i=1,mp1=1,mp2=m[3];i<=m[2];++i){
		ll y=b[2][i];ll res=Dist(2,y);
		while(mp1<=m[1]&&!Valid2_(1,3,y,b[1][mp1],m[1]+m[3])) ++mp1;
		while(mp2>=1&&!Valid1_(1,3,y,y+b[3][mp2],m[1]+m[3])) --mp2;
		if(mp1<=m[1]&&Valid1_(1,3,y,b[1][mp1],m[1]+m[3])){
			res+=Dist(1,b[1][mp1])+Dist(3,b[1][mp1]-y);
		}else if(mp2>=1&&Valid2_(1,3,y,y+b[3][mp2],m[1]+m[3])){
			res+=Dist(1,y+b[3][mp2])+Dist(3,b[3][mp2]);
		}else res=Inf;
		chkmin(ans,res);
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-06-19 12:04  Alan_Zhao_2007  阅读(50)  评论(0编辑  收藏  举报