题目
https://gmoj.net/senior/#main/show/6087
题解
发现
a
n
s
=
1
−
∏
i
=
l
r
(
1
−
a
i
x
)
ans=1-\prod_{i=l}^r \left(1-\frac{a_i}{x}\right)
ans=1−i=l∏r(1−xai)
∏
\prod
∏ 比较难搞,就把它变成
∑
\sum
∑ 吧!
a
n
s
=
1
−
e
∑
i
=
l
r
ln
(
1
−
a
i
x
)
ans=1-e^{\sum_{i=l}^r \ln\left(1-\frac{a_i}{x}\right)}
ans=1−e∑i=lrln(1−xai)
ln
\ln
ln 比较难搞,就把它变成多项式函数吧!
为了方便处理,先弄出 ln ( x + 1 ) \ln(x+1) ln(x+1) 的情况,再把 − a i x -\frac{a_i}{x} −xai 代进去。
令 f ( x ) = ln ( x + 1 ) f(x)=\ln(x+1) f(x)=ln(x+1) 。
由 泰勒公式 ,得
f
(
x
)
=
∑
i
=
0
∞
f
(
i
)
(
x
0
)
i
!
(
x
−
x
0
)
i
f(x)=\sum_{i=0}^{\infty} \frac{f^{(i)}(x_0)}{i!}(x-x_0)^i
f(x)=i=0∑∞i!f(i)(x0)(x−x0)i
其中
f
(
i
)
(
x
)
f^{(i)}(x)
f(i)(x) 表示
f
(
x
)
f(x)
f(x) 的
i
i
i 阶导数。
先求出 ( ln ( x ) ) ′ (\ln(x))' (ln(x))′ 。
设
y
=
ln
x
y=\ln x
y=lnx ,那么
(
ln
x
)
′
=
1
(
e
y
)
′
=
1
e
y
=
1
x
(\ln x)'=\frac{1}{(e^y)'}=\frac{1}{e^y}=\frac{1}{x}
(lnx)′=(ey)′1=ey1=x1
所以
f
′
(
x
)
=
[
ln
(
x
+
1
)
]
′
(
x
+
1
)
′
=
1
x
+
1
=
(
x
+
1
)
−
1
f
′
′
(
x
)
=
−
(
x
+
1
)
−
2
f
′
′
′
(
x
)
=
2
(
x
+
1
)
−
3
⋯
f
(
n
)
(
x
)
=
(
−
1
)
n
+
1
(
n
−
1
)
!
(
x
+
1
)
−
n
\begin{aligned} f'(x)&=[\ln(x+1)]'(x+1)'=\frac{1}{x+1}=(x+1)^{-1}\\ f''(x)&=-(x+1)^{-2}\\ f'''(x)&=2(x+1)^{-3}\\ &\cdots\\ f^{(n)}(x)&=(-1)^{n+1}(n-1)!(x+1)^{-n} \end{aligned}
f′(x)f′′(x)f′′′(x)f(n)(x)=[ln(x+1)]′(x+1)′=x+11=(x+1)−1=−(x+1)−2=2(x+1)−3⋯=(−1)n+1(n−1)!(x+1)−n
那么
f
(
x
)
=
∑
i
=
0
∞
f
(
i
)
(
x
0
)
i
!
(
x
−
x
0
)
i
=
∑
i
=
0
∞
f
(
i
)
(
0
)
i
!
x
i
令
x
0
=
0
=
∑
i
=
1
∞
(
−
1
)
i
−
1
(
i
−
1
)
!
i
!
x
i
ln
1
=
0
=
∑
i
=
1
∞
(
−
1
)
i
−
1
x
i
i
\begin{aligned} f(x)&=\sum_{i=0}^{\infty} \frac{f^{(i)}(x_0)}{i!}(x-x_0)^i\\ &=\sum_{i=0}^{\infty} \frac{f^{(i)}(0)}{i!}x^i &\text{令 $x_0=0$ }\\ &=\sum_{i=1}^{\infty} \frac{(-1)^{i-1}(i-1)!}{i!}x^i &\text{$\ln 1=0$}\\ &=\sum_{i=1}^{\infty} \frac{(-1)^{i-1}x^i}{i} \end{aligned}
f(x)=i=0∑∞i!f(i)(x0)(x−x0)i=i=0∑∞i!f(i)(0)xi=i=1∑∞i!(−1)i−1(i−1)!xi=i=1∑∞i(−1)i−1xi令 x0=0 ln1=0
将
−
a
i
x
-\frac{a_i}{x}
−xai 代入,得
∑
i
=
l
r
ln
(
1
−
a
i
x
)
=
∑
i
=
l
r
f
(
a
i
x
)
=
−
∑
i
=
l
r
∑
j
=
1
∞
a
i
j
j
⋅
x
j
\begin{aligned} \sum_{i=l}^r \ln\left(1-\frac{a_i}{x}\right)&=\sum_{i=l}^r f\left(\frac{a_i}{x}\right)\\ &=-\sum_{i=l}^r \sum_{j=1}^{\infty} \frac{a_{i}^j}{j\cdot x^j} \end{aligned}
i=l∑rln(1−xai)=i=l∑rf(xai)=−i=l∑rj=1∑∞j⋅xjaij
在实际上做的时候,第二重循环只用枚举到
20
20
20 精度就足够了,因此用 前缀和 维护一个
∑
i
=
l
r
∑
j
=
1
20
a
i
j
j
\sum_{i=l}^r \sum_{j=1}^{20} \frac{a_{i}^j}{j}
∑i=lr∑j=120jaij 就可以了。
为了防止
a
i
j
a_i^j
aij 爆 long double
,可以把每一个
a
i
a_i
ai 和
x
x
x 都除以一个
max
i
=
1
n
a
i
\max_{i=1}^n a_i
maxi=1nai 。
还可以发现当 a i x \frac{a_i}{x} xai 比较大的时候,由于它离 x 0 x_0 x0 远,会有较大误差。这时只要暴力地把这些 a i x \frac{a_i}{x} xai 乘在一起而不把它们放到 ∑ \sum ∑ 中计算即可,如果这些 a i x \frac{a_i}{x} xai 较多答案就是 0 0 0 了。可以把阈值设置为 0.5 0.5 0.5 。
代码
#include<cstdio>
#include<cmath>
using namespace std;
#define fo(i,l,r) for(i=l;i<=r;++i)
typedef long double LF;
char p[15],buf[100005],*l=buf,*r=buf;
inline char gc()
{return l==r&&(r=(l=buf)+fread(buf,1,100005,stdin),l==r)?EOF:*l++;}
inline void read(int &k)
{
char ch;while(ch=gc(),ch<'0'||ch>'9');k=ch-48;
while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-48;
}
#define N 600005
const int lim=20;
LF a[N],s[N][lim+1],x,ans1,ans2;
int A[N],f[N][20],highbit[N];
inline int mymax(int x,int y){return a[x]>a[y]?x:y;}
void solve(int l,int r)
{
if(l>r) return;
int mid=mymax(f[r-(1<<highbit[r-l+1])+1][highbit[r-l+1]],f[l][highbit[r-l+1]]);
if(a[mid]/x>0.5)
{
ans2*=1-a[mid]/x;
if(ans2<1e-7) return;
solve(l,mid-1),solve(mid+1,r);
}
else
{
LF tmp=x;
for(register int i=1;i<=lim;++i,tmp*=x)
ans1-=(s[r][i]-s[l-1][i])/tmp;
}
}
int main()
{
freopen("orz.in","r",stdin);
freopen("orz.out","w",stdout);
register int i;
int j,k,n,q,l,r,y,maxx=0;
LF max,tmp;
read(n),read(q);
fo(i,1,n)
{
read(A[i]);
if(A[i]>maxx) maxx=A[i];
}
max=maxx;
fo(i,1,n) a[i]=A[i]/max;
j=0;
fo(i,1,n)
{
if(i==1<<j+1) ++j;
highbit[i]=j;
}
fo(i,1,n) f[i][0]=i;
fo(j,1,19)
{
k=n-(1<<j)+1;
fo(i,1,k)
f[i][j]=mymax(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
fo(i,1,n)
{
tmp=a[i];
fo(j,1,lim)
{
s[i][j]=s[i-1][j]+tmp/j,
tmp*=a[i];
}
}
while(q--)
{
read(l),read(r),read(y);
x=y/max,ans1=0,ans2=1;
solve(l,r);
printf("%.7Lf\n",1-exp(ans1)*ans2);
}
return 0;
}