ISIJ 2021 Training Contest 1
阿新 • • 發佈:2021-06-19
連結: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\) 中一定有至少一個會取 \(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\)
如果一個數 \(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; }