题解 codechef CHEFATs

两天来唯一一道可做题……其他的都是什么神仙题啊【拍桌】

因为要维护

∏ i = l r ( 1 − p i ) \prod_{i=l}^{r} (1-p_i) i=lr(1pi)

这个东西,然后还有一个区间乘,直接搞就算是用线段树维护也肯定会 T \text{T} T,考虑用别的方法维护。

此时会想到一个常用技巧,把 ∏ \prod 转换成 ∑ \sum 来做,也就是借助 ln ⁡ \ln ln 函数来把乘变成加,再用线段树就很好维护了。

所以我们可以得到:

∏ i = l r ( 1 − p i ) = e ∑ i = l r ln ⁡ ( 1 − p i ) \prod_{i=l}^{r}(1-p_i)=e^{\sum_{i=l}^{r}\ln(1-p_i)} i=lr(1pi)=ei=lrln(1pi)

但是 ln ⁡ ( 1 − p i ) \ln(1-p_i) ln(1pi) 这个东西也不好维护,考虑 Taylor \text{Taylor} Taylor 展开,可以得到:

ln ⁡ ( 1 − x ) = − ∑ i = 1 ∞ x i i \ln(1-x)=-\sum_{i=1}^{\infty}\frac{x^i}{i} ln(1x)=i=1ixi

维护个 100 100 100 项就行了。

#include
#define MAXN 100005
#define S 100
using namespace std;
int n,m;
double a[MAXN],t[MAXN<<2][S+5],tag[MAXN<<2];
void PushUp(int rt)
{
	for(int i=1;i<=S;i++) t[rt][i]=t[rt<<1][i]+t[rt<<1|1][i];
}
void Add(int rt,double val)
{
	tag[rt]*=val;
	double cnt=val;
	for(int i=1;i<=S;i++)
	{
		t[rt][i]*=cnt;
		cnt*=val;
	}
}
void PushDown(int rt)
{
	if(tag[rt]!=1)
	{
		Add(rt<<1,tag[rt]);
		Add(rt<<1|1,tag[rt]);
		tag[rt]=1;
	}
}
void BuildSegmentTree(int rt,int l,int r)
{
	tag[rt]=1;
	if(l==r)
	{
		double cnt=a[l];
		for(int i=1;i<=S;i++)
		{
			t[rt][i]=cnt;
			cnt*=a[l];
		}
		return;
	}
	int mid=l+r>>1;
	BuildSegmentTree(rt<<1,l,mid);
	BuildSegmentTree(rt<<1|1,mid+1,r);
	PushUp(rt);
}
void Modify(int rt,int l,int r,int tl,int tr,double T)
{
	if(tl<=l && r<=tr)
	{
		Add(rt,T);
		return;
	}
	PushDown(rt);
	int mid=l+r>>1;
	if(tl<=mid) Modify(rt<<1,l,mid,tl,tr,T);
	if(tr>mid) Modify(rt<<1|1,mid+1,r,tl,tr,T);
	PushUp(rt);
}
double Query(int rt,int l,int r,int tl,int tr)
{
	double res=0;
	if(tl<=l && r<=tr)
	{
		for(int i=1;i<=S;i++) res+=t[rt][i]/i;
		return res;
	}
	PushDown(rt);
	int mid=l+r>>1;
	if(tl<=mid) res+=Query(rt<<1,l,mid,tl,tr);
	if(tr>mid) res+=Query(rt<<1|1,mid+1,r,tl,tr);
	return res;
}
int main()
{
	freopen("food.in","r",stdin);
	freopen("food.out","w",stdout);
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
	BuildSegmentTree(1,1,n);
	while(m--)
	{
		int opt,x,y;
		double z;
		scanf("%d %d %d",&opt,&x,&y);
		if(!opt) printf("%.8lf\n",exp(-Query(1,1,n,x,y)));
		else
		{
			scanf("%lf",&z);
			Modify(1,1,n,x,y,z);
		}
	}
	return 0;
}

你可能感兴趣的:(c++,题解,数据结构)