题意: DDOS 攻击的总流量值为 (L),寓所服务器的吞吐量为 (d)。
博丽灵梦可以多次使用魔法消耗 DDOS 攻击的流量:
设当前剩余攻击流量为 (l) ,那么灵梦可以使用 (l+d) 的魔法值,将剩余攻击流量变为一个随机的浮点数 (l' (0 leq l' < l)) 。
服务器具有吞吐量 (d) ,故一旦剩余攻击流量 (l le d) 时,服务器会立即消耗掉所有攻击流量。
求对于当前流量 (L) ,灵梦需要使用的总魔法值的期望。
设当前攻击流量为 (x(x>d)) 时,消耗的魔法能力期望为 (f(x)) ,有
[f(x)=x+d+frac{1}{x}int_0^xf(t)dt
]
两边乘 (x)
[xf(x)=x^2+dx+int_0^xf(t)dt
]
两边微分
[f(x)+xf'(x)=2x+d+f(x)
]
即
[f'(x)=2+frac{d}{x}
]
两边积分
[f(x)=2x+d ln x +C
]
代入特殊值
[lim_{x o {d^+}f(x)=2d
]
解得
[C=-d ln d
]
即
[ f(x)=left{
egin{array}{rcl}
0 && {0 le x le d} \
2x+d ln x -d ln d && {x > d} \
end{array}
ight.
]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int T;
while(~scanf("%d", &T)) {
while(T--) {
double x, d;
scanf("%lf%lf", &x, &d);
if(x > d)
printf("%.2f
", 2.0 * x + d * log(x) - d * log(d));
else
printf("0.00
");
}
}
}
因为精度要求不高,也可以转为整数模拟积分:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int T = 500000;
double dp[5 * T + 100];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int u;
scanf("%d", &u);
while(u--) {
double l, d;
scanf("%lf%lf", &l, &d);
memset(dp, 0, sizeof(dp));
int L = l * T, D = d * T;
double sum = 0;
for(int i = D + 1; i <= L; ++i) {
dp[i] = sum / (i - 1) + i + D;
sum += dp[i];
}
printf("%.2f
", dp[L] / T);
}
return 0;
}
当时自己想的那个代码恰好也是50万,不过多了一个ceil,导致误差:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int T = 500000;
double dp;
double predp;
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int u;
scanf("%d", &u);
while(u--) {
double l, d;
scanf("%lf%lf", &l, &d);
int D = d * T;
dp = 0.0;
predp = 0.0;
int L = ceil(l * T);
for(int i = D + 1; i <= L; ++i) {
dp = predp / (i - 1) + (d + i / (double)T);
predp += dp;
}
printf("%.2f
", dp);
}
return 0;
}
去掉无关的常数之后,20万的精度是足够了的。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int T = 200000;
double dp;
double predp;
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int u;
scanf("%d", &u);
while(u--) {
double l, d;
scanf("%lf%lf", &l, &d);
int D = d * T;
dp = 0.0;
predp = 0.0;
int L = l * T;
for(int i = D + 1; i <= L; ++i) {
dp = predp / (i - 1) + D + i;
predp += dp;
}
printf("%.2f
", dp / T);
}
return 0;
}