これは落ち着いてやったら自力で解けた。
http://codeforces.com/contest/293/problem/D
問題
2次元座標上で、凸図形を構成するN個の頂点群が与えられる。
この凸図形の中にある任意の2点を選んだ時、その2点を対角線とする正方形の面積の期待値を求めよ。
解法
正方形の面積=2点間の距離の2乗の半分、なので、全部の2点間の距離の2乗の総和を求めればよい。
この際三平方の定理より、2点の距離の2乗和=(2点のX座標の差の2乗和)+(2点のY座標の差の2乗和)なので、X座標とY座標それぞれに差の2乗和を取って足せばよい。
以下X座標の差の2乗和を考える。
まず凸図形内において、各X座標に相当する格子点の数P[x]を列挙していく。
この処理はO(N+maxX)程度で終えることができる。
あとは距離の2乗和については、下記の容量で累積和を使ってO(maxX)で求めることができる。
Codeforces #231 Div2. E. Lightbulb for Minister - kmjp's blog
X座標がxにあるP[x]個の点と、z<xにある各頂点との二乗和は
となるので、とを管理しておけばよい。
あとは同じ処理をY座標に関して行う。
int N,X[100006],Y[100006]; vector< vector<pair<int,int> > > H; void solve() { int i,j,k,l,r,x,y; string s; H.resize(2000005); cin>>N; FOR(i,N) cin>>X[i]>>Y[i], X[i]+=1000000, Y[i]+=1000000; double ret=0; double T; FOR(k,2) { T=0; FOR(x,2000001) H[x].clear(); FOR(i,N) { H[X[i]].push_back(make_pair(Y[i],Y[i])); if(X[i]!=X[(i+1)%N]) { int dx=(X[i]<X[(i+1)%N])?1:-1; for(x=X[i]+dx;x!=X[(i+1)%N];x+=dx) { ll dy=1LL*(x-X[i])*(Y[(i+1)%N]-Y[i]); ll y2=Y[i]+dy/(X[(i+1)%N]-X[i]); if((dy>=0) ^ (X[(i+1)%N]<X[i])) H[x].push_back(make_pair(y2,y2+((dy%(X[(i+1)%N]-X[i])!=0)))); else H[x].push_back(make_pair(y2-(dy%(X[(i+1)%N]-X[i])!=0),y2)); } } } double S1=0,S2=0; FOR(x,2000001) if(H[x].size()) { int mf=H[x][0].first,ms=H[x][0].second; FOR(i,H[x].size()) mf=max(mf,H[x][i].first),ms=min(ms,H[x][i].second); int h=mf-ms+1; if(h<=0) continue; ret += h*(T*x*x-2LL*x*S1+S2); T+=h; S1+=1LL*h*x; S2+=1LL*h*x*x; } FOR(i,N) swap(X[i],Y[i]); } _P("%.12lf\n",ret/(T-1.0)/T); }
まとめ
過去のCodeforcesの知識が活きて良かった。