yukicoder No.456 Millions of Submits!
問題URL : http://yukicoder.me/problems/no/456
問題概要
整数a,bと実数tがm回与えられる.
各a,b,tについて以下の式を満たす最大のnを計算せよ.
解法
mが最大10^6と大きいため,単純に二分探索を行うとTLEしてしまう.
そこでaとbで場合分けを行う.
(1) a = 0 or b = 0 のとき
計算式は
or
と式変形できるため簡単に計算できる.
(2) それ以外(a > 0 and b > 0) のとき
nの取りうる値の範囲について考えてみると,
a=1, b=1, t=10 のとき n = 5.72 ... で最大となり,
a=10, b=10, t=0.1 のとき n = 1.62 ... で最小となる.
よって探索範囲は1 < n < 6 とすれば十分だと分かる.
許容誤差は10^-9なので log 5/10^-9 = 32.219 ... < 33 回以上探索を繰り返せば精度は足りる.
あとは,powの計算を繰り返し二乗法で計算することでTLEせずに計算することができる.
(std::powを使うとTLE)
(for文でpowを計算しても間に合うらしい...)
コード
double mypow(double x, int y) { double a = 1; while(y) { if(y & 1) a = a * x; x = x * x; y >>= 1; } return a; } inline double f(int a, int b, double x) { return mypow(x, a) * mypow(log(x), b); } void mainmain() { int m; scanf("%d", &m); rep(i, m) { int a, b; double t; scanf("%d%d%lf", &a, &b, &t); if(a == 0) { double ans = exp(pow(t, 1. / b)); printf("%.10lf\n", ans); continue; } else if(b == 0) { double ans = pow(t, 1. / a); printf("%.10lf\n", ans); continue; } double l = 1; double r = 6; rep(j, 35) { double mid = (l + r) / 2; double val = f(a, b, mid); if(t <= val) r = mid; else l = mid; } printf("%.10lf\n", l); } }
コメント
ごり押しでごめんなさい