E. The Contest 解析(思維、前綴和)
Codeforce 1257 E. The Contest 解析(思維、前綴和)
今天我們來看看CF1257E
題目連結
題目
有三個籃子,放數字\(1\sim n\)。求最小的數字移動次數,使得三個籃子裡的數字由小排到大。
前言
很久沒有寫題目了,主要是自己本科也不是做電腦的,而且寫難度2000的題目真的遇到很多挫折...,常常寫到想放棄。
這題也搞了很久,看了別人的解析才知道怎麼做,腦袋打結了一整天。
@copyright petjelinux 版權所有
觀看更多正版原始文章請至petjelinux的blog
觀看更多正版原始文章請至petjelinux的blog
想法
這題其實有dp解法,但是這篇文章就不講了。
第一眼看到這題目,可能會覺得就是要找到一組數字\([l,r]\)表示第一個籃子放\([1,l]\),第二個籃子放\([l+1,r-1]\),第三個籃子放\([r,n]\)。但是\(n\le2e5\),所以我們應該是遍歷\(l\)從\(1\sim n\),然後快速地找出哪個\(r\)最好。
令\(cnt[i][j]\)表示第\(i\)個籃子擁有幾個\([1,j]\)的數字。
假設目前決定好了\([l,r]\),那麼需要的步數即:\(cnt[1][l+1\sim n]+cnt[2][1\sim l]+cnt[2][r\sim n]+cnt[3][1\sim r-1]\)
也就是我們計算要幾步才能把原本不在正確的籃子裡的數字放到正確的籃子裡。
假設已經固定了\(l\),\(cnt[1][l+1\sim n]+cnt[2][1\sim l]\)就可以用前綴和輕鬆算出來,接著我們只要決定\(cnt[2][r\sim n]+cnt[3][1\sim r-1]\)到底是哪個\(r\)才會最小就好。
而只要事先計算對於每個後綴\([r\sim n]\),最小的\(cnt[2][r\sim n]+cnt[3][1\sim r-1]\)是多少,就可以解決這題了。
程式碼:
const int _n=2e5+10;
int t,n,m,k[3],pos[_n],cnt[3][_n],mn[_n],ans=0x7f7f7f7f;
main(void) {ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
rep(_,0,3){cin>>k[_];n+=k[_];}
rep(_,0,3)rep(i,0,k[_]){cin>>t;pos[t]=_;}
rep(i,1,n+1)rep(_,0,3)cnt[_][i]=cnt[_][i-1]+(pos[i]==_);
mn[n+1]=cnt[2][n];
per(i,1,n+1)mn[i]=min(mn[i+1],cnt[1][n]-cnt[1][i-1]+cnt[2][i-1]);
rep(i,0,n+1)ans=min(ans,cnt[0][n]-cnt[0][i]+cnt[1][i]+mn[i+1]);
cout<<ans;
return 0;
}
標頭、模板請點Submission看
Submission