【题解】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;
}
posted @ 2021-12-26 11:59  HyperSQ  阅读(28)  评论(0)    收藏  举报