うーん、微妙な出来。
https://beta.atcoder.jp/contests/arc094/tasks/arc094_b
問題
多くの人がコンテストに参加し、2問の問題を解いた。
それぞれの問題で、同着なく1位から順位が着く。
参加者のスコアは、2回の順位の積である。
2回のコンテストの順位がA,Bだった人がいた場合、それよりスコアの低い人は最大何人いるか。
解法
A≦Bとする。
1問目で1~(A-1)位だった人は2問目で(B+A-1)~(B+1)位を取ると全員問題の人より低いスコアになる。
(1問目がA-x、2問目をB+xとするとスコアがAB+(B-A)*x-x*x<AB)
また、2問目で1~(A-1)位だった人も同様に1問目で(A+B-1)~(B+1)位を取ると全員問題の人より低いスコアになる。
この時点で2*(A-1)人いるのが確定である。
残りは1問目の順位が(A+1)~B位で2問目の順位がA~(B-1)位の組み合わせが可能性として残っている。
二分探索でこのうち題意を満たす人数xを求めよう。
1問目が(A+1)~(A+x)の人が対応して2問目が(A+x-1)~A位を取るようにしたとき、全員スコアがAB未満となるxの最大値を求める。
実際にはxに対し全員AB以下かチェックする必要はなく、中心付近だけでよい。
int Q; ll A,B; void solve() { int i,j,k,l,r,x,y; string s; cin>>Q; while(Q--) { cin>>A>>B; if(A>B) swap(A,B); ll ret=2*(A-1); int num=0; for(i=29;i>=0;i--) { num+=1<<i; if(A+num>B) { num-=1<<i; continue; } int ng=0; for(x=num/2-2;x<=num/2+2;x++) { if(x<=0 || x>num) continue; if((A+x)*(A+num-x)>=A*B) ng=1; } if(ng) num-=1<<i; } ret+=num; cout<<ret<<endl; } }
まとめ
なんか妙に手間取った。