1. 程式人生 > 其它 >ISIJ 2021 Training Contest 1

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;
}