すいませんゴリ押ししました。
http://yukicoder.me/problems/no/454
問題
非負実数Xが与えられる。
を求めよ。
誤差は10^-9まで許容される。
解法
とすると、真の解をAとしたときとなる。
ここでA_nの真の解に対する誤差を考える。
右辺はnの逆2乗に対する和なので、おおよそnに反比例することが予想される。
そのため、愚直にA_nを計算する場合n=10^9程度まで処理すれば誤差が10^-9以下になることが期待できる。
実際、1.2×10^9回ループするとこの問題はACできる。
ただ除算が重いため、除算を減らすよう若干の工夫が必要である。
というか自分はそれでゴリ押しした(ソース中コメント部参照)。
改めてを考える。
この総和の部分は、下記の通り2つの積分値で挟み込める。
両端の積分を計算すると、以下のようになる。
この時、両側の差はと大よそnの逆2乗に比例する。
よって、A_nの極限を求めるのではなく、A_n+1/(X+n)を求めれば、n=10^5程度までの計算で誤差が10^-9以下になる。
void solve() { int i,j,k,l,r,x,y; string s; double X; cin>>X; double ret=0; /* i=1200000000; X+=i; for(;i>=100;i-=3) { double a=(X*X); double b=(X-1)*(X-1); double c=(X-2)*(X-2); double ab=a*b; ret += (ab+c*(a+b))/(ab*c); X-=3; } for(;i>=1;i--) { ret += 1.0/(X*X); X--; } */ for(i=1;i<1000000;i++) { ret += 1/((X+i)*(X+i)); } ret += 1/(X+i); _P("%.12lf\n",ret); }
まとめ
本番ガンマ関数とか、SSEによる高速化とかいろいろ調べていたけど、結局ゴリ押し…。