DTOJ#5071. 切面包

H 有条一长长的面包。这条面包由 n n n 段组成。

每当有朋友到小 H 的家里玩,小 H 就会切下这块面包的一段,分享给朋友们。之后,小 H 又会重新制作和之前完全一样的若干段面包填充切下的部分。

面包被切下时,有可能会裂开,第 i i i 段面包被切下时裂开的概率为 p i 998244352 \frac{p_i}{998244352} 998244352pi。小 H 想让朋友尽可能开心,于是会把裂开的面包自己吃掉,而用没有裂开的面包招待朋友。小 H 特别喜欢分块,因此,如果小 H x x x 段连续的没有裂开的面包,则朋友的开心度为 x 2 x^2 x2

有时,小 H 也会对一段面包进行加工,加工会改变面包裂开的概率。

你需要在每次小 H 切蛋糕之前,回答他朋友的期望开心度是多少。

第一行两个整数 n , m n, m n,m,分别表示面包的长度和时间的次数。

第二行 n n n 个整数 p 1 , p 2 , … , p n p_1, p_2,\dots, p_n p1,p2,,pn,表示每段面包初始时裂开的概率。

接下来 m m m 行,每行表示一个事件:

  • 1   x i   q i 1 \ x_i\ q_i 1 xi qi 表示小 H 加工了第 x i x_i xi 段面包,加工后 p x i p_{x_i} pxi 变成了 q i q_i qi

  • 2   l i   r i 2 \ l_i\ r_i 2 li ri 表示小 H 询问若切下 [ l i , r i ] [l_i, r_i] [li,ri] 内的面包,朋友的期望开心度是多少。

对每个 2 2 2 事件,输出一个整数,表示朋友的期望开心度对 998244353 998244353 998244353 取模后的值。

样例输入
3 5
499122176 499122176 499122176
2 1 1
2 1 2
2 1 3
1 2 0
2 1 3
样例输出
499122177
249561089
748683266
1
样例解释

在第一次询问中,唯一的一段面包有 1 2 \frac{1}{2} 21 的概率裂开,开心度为 0 0 0;有 1 2 \frac{1}{2} 21 的概率不会裂开,开心度为 1 1 1。所以期望的开心度为 1 2 × 0 + 1 2 × 1 = 1 2 \frac{1}{2}\times 0 +\frac{1}{2}\times 1 =\frac{1}{2} 21×0+21×1=21

在第二次询问中,有 1 2 × 1 2 = 1 4 \frac{1}{2}\times\frac{1}{2}=\frac{1}{4} 21×21=41 的概率两段面包都裂开,开心度为 0 0 0;有 3 4 \frac{3}{4} 43 的概率不会裂开,开心度为 1 1 1。所以期望的开心度为 1 4 × 0 + 3 4 × 1 = 3 4 \frac{1}{4}\times 0 +\frac{3}{4}\times 1 =\frac{3}{4} 41×0+43×1=43

在第三次询问中,有 1 2 × 1 2 × 1 2 = 1 8 \frac{1}{2}\times\frac{1}{2}\times\frac{1}{2}=\frac{1}{8} 21×21×21=81 的概率三段面包都裂开,开心度为 0 0 0;有 1 2 × 1 2 × 1 2 = 1 8 \frac{1}{2}\times\frac{1}{2}\times\frac{1}{2}=\frac{1}{8} 21×21×21=81 的概率第一段和第三段面包没有裂开而第二段面包裂开,开心度为 2 2 = 4 2^2=4 22=4;有 3 4 \frac{3}{4} 43 的概率开心度为 1 1 1。所以期望的开心度为 1 8 × 0 + 1 8 × 4 + 3 4 × 1 = 5 4 \frac{1}{8}\times 0 +\frac{1}{8}\times 4+\frac{3}{4}\times 1 =\frac{5}{4} 81×0+81×4+43×1=45

在第四次询问中,第二段面包一定不会裂开,此时第一段和第三段面包是否裂开不会影响开心度,所以期望的开心度为 1 1 1

对于所有测试点,满足 1 ≤ n , m ≤ 1 0 5 , 0 ≤ p i , q i ≤ 998244352 , 1 ≤ x i ≤ n , 1 ≤ l i ≤ r i ≤ n 1\leq n,m\leq 10^5,0\leq p_i,q_i\leq 998244352,1\leq x_i \leq n,1\leq l_i \leq r_i\leq n 1n,m105,0pi,qi998244352,1xin,1lirin

本题共有 5 5 5 个测试点,每个测试点 20 20 20 分:

测试点 1 1 1 1 ≤ n , m ≤ 20 1 \leq n, m \leq 20 1n,m20

测试点 2 2 2 p i = 499122176 p_i = 499122176 pi=499122176,没有 1 1 1 事件。

测试点 3 3 3:没有 1 1 1 事件。

测试点 4 4 4 1 ≤ n , m ≤ 2 × 1 0 3 1 \leq n, m \leq 2 \times 10^3 1n,m2×103

测试点 5 5 5:无特殊限制。

jly csp2019 模拟1

爆踩标算!

p i p_i pi为裂开的概率。
首先对于 [ l , r ] [l,r] [l,r]中的每一段,可以用段首来表示,即若 j = i + 1 j=i+1 j=i+1,即有 p i ( 1 − p j ) p_i(1-p_j) pi(1pj)的概率贡献 1 1 1
但两段首不能相邻。
∵ E ( x 2 ) = E [ ( x 1 + x 2 + x 3 + . . . + x k ) × ( x 1 + x 2 + x 3 + . . . + x k ) ] = E ( x i 2 ) + 2 E ( x i × x j ) \because E(x^2)\\=E[(x_1+x_2+x_3+...+x_k)\times(x_1+x_2+x_3+...+x_k)]\\=E(x_i^2)+2E(x_i\times x_j) E(x2)=E[(x1+x2+x3+...+xk)×(x1+x2+x3+...+xk)]=E(xi2)+2E(xi×xj)
q i = p i − 1 ( 1 − p i ) q_i=p_{i-1}(1-p_i) qi=pi1(1pi)
∵ \because 贡献为1
∴ a n s = ∑ ( q i ) + 2 ∑ ( q i q j ) [ a b s ( i − j ) ! = 1 ] \therefore ans\\=\sum(q_i)+2\sum(q_iq_j)[abs(i-j)!=1] ans=(qi)+2(qiqj)[abs(ij)!=1]
即可用线段树维护
注意:区间开头的 q i = ( 1 − p i ) q_i=(1-p_i) qi=(1pi)
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include<bits/stdc++.h>
#define N 100005
using namespace std;
const int mod=998244353;
inline int read(){
	int x=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	return x*f;
}
inline int power(int x,int c){
	int now=1;
	while(c){
		if(c&1)now=1ll*now*x%mod;
		x=1ll*x*x%mod;c>>=1;
	}
	return now;
}
int pe[N];
struct seg{
	int l,r,dou,sum;
}t[N<<2];
inline seg up(seg A,seg B){
	seg p;p.l=A.l,p.r=B.r;
	int tmp=1ll*(1-pe[A.r])*pe[B.l]%mod,pre=pe[B.l],r=(B.l+1<=B.r)?1ll*(1-pe[B.l])*(pe[B.l+1])%mod:0;
	B.sum=(B.sum-pre)%mod;B.dou=(B.dou-1ll*B.sum*pre%mod)%mod;B.dou=(B.dou+1ll*r*pre%mod)%mod;B.dou=(B.dou+1ll*B.sum*tmp%mod)%mod;B.dou=(B.dou-1ll*r*tmp%mod)%mod;
	B.sum=(B.sum+tmp)%mod;
	pre=(A.l+1<=A.r)?1ll*(1-pe[A.r-1])*pe[A.r]%mod:pe[A.r];
	p.sum=(A.sum+B.sum)%mod;p.dou=(A.dou+B.dou)%mod;p.dou=(p.dou+1ll*A.sum*B.sum%mod)%mod;p.dou=(p.dou-1ll*pre*tmp%mod)%mod;
	return p;
}
void build(int p,int l,int r){
	t[p].l=l,t[p].r=r;t[p].dou=0,t[p].sum=0;
	if(l==r){
		t[p].sum=pe[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
	t[p]=up(t[p<<1],t[p<<1|1]);
}
void change(int p,int l,int val){
	if(t[p].l==t[p].r){
		pe[t[p].l]=val;
		t[p].sum=val;
		return ;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid)change(p<<1,l,val);
	else change(p<<1|1,l,val);
	t[p]=up(t[p<<1],t[p<<1|1]);
}
seg ask(int p,int l,int r){
	if(t[p].l>=l&&t[p].r<=r){
		return t[p];
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(r<=mid)return ask(p<<1,l,r);
	if(l>mid)return ask(p<<1|1,l,r);
	return up(ask(p<<1,l,r),ask(p<<1|1,l,r));
}
int main(){
	int n=read(),m=read(),dow=power(998244352,mod-2);
	for(int i=1;i<=n;++i)pe[i]=1ll*read()*dow%mod,pe[i]=(1-pe[i]+mod)%mod;
	build(1,1,n);
	while(m--){
		int op=read();
		if(op==1){
			int x=read(),pp=read();pp=1ll*pp*dow%mod;pp=(1-pp+mod)%mod;
			change(1,x,pp);
		}else{
			int l=read(),r=read(),ans;
			seg now=ask(1,l,r);
			ans=(now.sum+1ll*2*now.dou%mod)%mod;
			printf("%d\n",(ans+mod)%mod);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值