【题解】CF138C Mushroom Gnomes - 2
调了很久发现是愚蠢的错误,麻了。
价值总和期望,考虑每一个蘑菇对答案的贡献。
单一蘑菇对答案的贡献为
\[z_i\prod(1-p_j)
\]
其中 \(p_j\) 表示能砸到该蘑菇的树的倒下概率。
可以将蘑菇的位置离散化后,用数据结构进行区间乘 \(1-p_j\),在统计蘑菇价值时使用单点查询。
可以考虑用线段树。
但树状数组其实也可以,我的老师提供了一个方案,考虑将概率换算为自然对数值,这样区间乘法就变成加法了,不怕精度问题。概率为 \(0\) 时特判一下,把区间标记为非法。很妙。
Code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int n,m,p;
ll vec[maxn*6],cnt,val[maxn*6];
ll a[maxn],b[maxn],l[maxn],r[maxn],h[maxn],z[maxn];
long double C[maxn*6];ll A[maxn*6];
void add(int x,int k){
while(x<=p){
A[x]+=k;
x+=-x&x;
}
}
void update(int x,long double k){
while(x<=p){
C[x]+=k;
x+=x&-x;
}
}
long double query(int x){
long double ret=0.0;
while(x){
ret+=C[x];
x-=x&-x;
}
return ret;
}
bool check(int x){
ll ret=0;
while(x){
ret+=A[x];
x-=x&-x;
}
return ret>0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld%lld",&a[i],&h[i],&l[i],&r[i]);
vec[++cnt]=a[i]-h[i];
vec[++cnt]=a[i];
vec[++cnt]=a[i]+h[i];
}
for(int i=1;i<=m;i++){
scanf("%lld%lld",&b[i],&z[i]);
vec[++cnt]=b[i];
}
for(int i=1;i<=cnt;i++){
val[i]=vec[i];
}
sort(val+1,val+cnt+1);
p=unique(val+1,val+cnt+1)-val-1;
for(int i=1;i<=n;i++){
int L=lower_bound(val+1,val+p+1,a[i]-h[i])-val;
int mid=lower_bound(val+1,val+p+1,a[i])-val;
int R=lower_bound(val+1,val+p+1,a[i]+h[i])-val;
if(!l[i]);
else if(100-l[i]) update(L,log(1.00-l[i]/100.0)),update(mid,-log(1.00-l[i]/100.0));
else add(L,1LL),add(mid,-1LL);
if(!r[i]);
else if(100-r[i]) update(mid+1,log(1.00-r[i]/100.0)),update(R+1,-log(1.00-r[i]/100.0));
else add(mid+1,1LL),add(R+1,-1LL);
}
long double ans=0.0;
for(int i=1;i<=m;i++){
int x=lower_bound(val+1,val+p+1,b[i])-val;
if(check(x)||!z[i]) continue;
ans+=exp(query(x))*z[i];
}
cout<<fixed<<setprecision(10)<<ans<<endl;
}

浙公网安备 33010602011771号