Codeforces 1264C Beautiful Mirrors with queries(线段树+期望)

Beautiful Mirrors with queries

time limit per test:2 seconds
memory limit per test:256 megabytes
Problem Description

Creatnx has n mirrors, numbered from 1 to n. Every day, Creatnx asks exactly one mirror “Am I beautiful?”. The i-th mirror will tell Creatnx that he is beautiful with probability p i 100 \frac{pi}{100} 100pi for all 1 ≤ i ≤ n.

Some mirrors are called checkpoints. Initially, only the 1st mirror is a checkpoint. It remains a checkpoint all the time.

Creatnx asks the mirrors one by one, starting from the 1-st mirror. Every day, if he asks i-th mirror, there are two possibilities:

  • The i-th mirror tells Creatnx that he is beautiful. In this case, if i = n Creatnx will stop and become happy, otherwise he will continue asking the i+1-th mirror next day;
  • In the other case, Creatnx will feel upset. The next day, Creatnx will start asking from the checkpoint with a maximal number that is less or equal to i.
    There are some changes occur over time: some mirrors become new checkpoints and some mirrors are no longer checkpoints. You are given q queries, each query is represented by an integer u: If the u-th mirror isn’t a checkpoint then we set it as a checkpoint. Otherwise, the u-th mirror is no longer a checkpoint.

After each query, you need to calculate the expected number of days until Creatnx becomes happy.

Input

The first line contains two integers n, q (2n,q2⋅105) — the number of mirrors and queries.

The second line contains n integers: p1,p2,…,pn (1≤pi≤100).

Each of q following lines contains a single integer u (2≤u≤n) — next query.

Output

Print q numbers – the answers after each query by modulo 998244353.

Sample Input

5 5
10 20 30 40 50
2
3
4
5
3

Sample Output

117
665496274
332748143
831870317
499122211

题意

n个点,每个点有 p i 100 \frac{pi}{100} 100pi的概率回答是。现规则如下:询问第 i 个点,如果其回答为是,若i=n,则游戏结束,否则第二天继续询问第i+1个点,如果第 i 个点回答为否,则下一天访问 <=i 的编号最大的checkpoint. 第1个点必然一直是checkpoint,初始其余点都不是checkpoint,每次会询问将第u个点变换一下(如果不是checkpoint则变为checkpoint,如果是则变为不是checkpoint),问每次改变后游戏结束的期望步数。

题解:

设数组 pi[i] 为第 i 个点回答是的概率,则单独考虑每一步,它回答为是的期望步数 e x [ i ] = 100 p i [ i ] ex[i] = \frac{100}{pi[i]} ex[i]=pi[i]100;首先不考虑其他checkpoint,游戏结束的期望步数是
E X = ( ( ( ( 0 + 1 ) ∗ e x [ 1 ] + 1 ) ∗ e x [ 2 ] . . . . + 1 ) ∗ e x [ n ] EX = ((((0+1)*ex[1] + 1)*ex[2]....+1)*ex[n] EX=((((0+1)ex[1]+1)ex[2]....+1)ex[n]

假如中间的 j 号点变成了checkpoint,则游戏结束的期望步数变为
E X = ( ( ( 0 + 1 ) ∗ e x [ 1 ] + 1 ) ∗ e x [ 2 ] . . . . + 1 ) ∗ e x [ j − 1 ] + ( ( ( 0 + 1 ) ∗ e x [ j ] + 1 ) ∗ e x [ j + 1 ] . . . . + 1 ) ∗ e x [ n ] EX = (((0+1)*ex[1]+1)*ex[2]....+1)*ex[j-1]+((( 0 + 1 )*ex[j]+1)*ex[j+1]....+1)*ex[n] EX=(((0+1)ex[1]+1)ex[2]....+1)ex[j1]+(((0+1)ex[j]+1)ex[j+1]....+1)ex[n]

而如果将是checkpoint的点 j,变为不是checkpoint,期望步数就会变成最上面的式子,而实际上就是将加号后面的那个0变为其加号前面的那个式子,而前面的式子正好是 1 号点到 j-1 号点回答为是期望步数。
而通过上式可以发现对于多个检查点,从1号点到n号点回答为是的期望步数,实际上就是 每个checkpoint到下一个checkpoint点之前的那个点回答为是的期望步数的总和 。所以可以考虑利用线段树或树状数组来维护点的信息,包括其是否为checkpoint,以及如果是checkpoint从其开始到下一个checkpoint之前的那个点回答为是的期望步数,线段树或树状数组维护区间内checkpoint点的数量和总期望步数。
而对于检查点i到检查点j之前的点回答为是的期望步数可以利用后缀来求。设suf[i]表示i号点开始,到n号点回答为是期望步数,而 s u m [ i ] = e x [ i ] ∗ e x [ i + 1 ] ∗ . . ∗ e x [ n ] sum[i]=ex[i]*ex[i+1]*..*ex[n] sum[i]=ex[i]ex[i+1]..ex[n]
利用上面的公式可以推出 s u f [ i ] = s u f [ i + 1 ] + e x [ i ] ∗ s u m [ i ] ; suf[i] = suf[i+1] + ex[i] * sum[i]; suf[i]=suf[i+1]+ex[i]sum[i];
利用后缀可以快速的求从i号点到 j 号点回答为是的期望步数为: e x = s u f [ i ] − s u f [ j + 1 ] s u m [ j + 1 ] ex=\frac{suf[i]-suf[j+1]}{sum[j+1]} ex=sum[j+1]suf[i]suf[j+1]

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-8
 
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 201000;
const int mod = 998244353;
int a[maxn], q[maxn*4];
bool stu[maxn];
//ex[i]:只考虑i号点回答为是的期望步数
//suf[i]:i号点为checkpoint到n号点回答为是的期望步数
//sum[i]:ex[i]*ex[i+1]*ex[i+2]*....*ex[n];
LL p[maxn*4], suf[maxn], sum[maxn], ex[maxn];
LL Pow(LL a, LL b);
void pushup(int k);
void creat(int l, int r, int k);
int getId(int l, int r, int x, int k);
int getSum(int l, int r, int al, int ar, int k);
void Update(int l, int r, int x, int y1, LL y2, int k);

int main()
{
	int n, m, i, j, k, l, r;
	scanf("%d %d", &n, &m);
	for(i=1;i<=n;i++){
		scanf("%d", &a[i]);
		ex[i] = (100*Pow(a[i], mod-2))%mod;
	}
	suf[n] = sum[n] = ex[n];
	suf[n+1] = 0, sum[n+1] = 1;
	for(i=n-1;i>=1;i--){
		sum[i] = (sum[i+1]*ex[i])%mod;
		suf[i] = (suf[i+1] + sum[i]) %mod;
	}
	creat(1, n, 1);
	Update(1, n, 1, 1, suf[1], 1);
	stu[1] = 1;

	while(m--)
	{
		scanf("%d", &i);
		stu[i] = !stu[i];
		j = getSum(1, n, 1, i, 1);
		if(!stu[i])
		{
			l = getId(1, n, j-1, 1);
			if(j == q[1])r = n+1;
			else r = getId(1, n, j+1, 1);
			//printf("l:%d r:%d\n", l, r);
			//将两段checkpoint的期望步数合为一段的期望步数
			Update(1, n, l, 0, 0, 1);
			Update(1, n, i, 0, 0, 1);
			LL ks = (suf[l]-suf[r]+mod)%mod * Pow(sum[r], mod-2)%mod;
			Update(1, n, l, 1, ks, 1);
		}
		else
		{
			l = getId(1, n, j, 1);
			if(j == q[1])r = n+1;
			else r = getId(1, n, j+1, 1);
			//printf("l:%d r:%d\n", l, r);
			Update(1, n, l, 0, 0, 1);
			LL ks = (suf[l]-suf[i]+mod)%mod * Pow(sum[i], mod-2)%mod;
			Update(1, n, l, 1, ks, 1);
			ks = (suf[i]-suf[r]+mod)%mod * Pow(sum[r], mod-2)%mod;
			Update(1, n, i, 1, ks, 1);
		}
		printf("%lld\n", p[1]);
	}
	return 0;
}

LL Pow(LL a, LL b)
{
	LL n = 1;
	while(b)
	{
		if(b&1)n = n*a % mod;
		a = a*a%mod;
		b /=2 ;
	}
	return n;
}

void pushup(int k)
{
	q[k] = q[2*k] + q[2*k+1];
	p[k] = (p[2*k] + p[2*k+1])%mod;
}

void creat(int l, int r, int k)
{
	q[k] = 0, p[k] = 0;
	if(l == r)return ;
	int mid = (l+r)/2;
	creat(l, mid, 2*k);
	creat(mid+1, r, 2*k+1);
}

void Update(int l, int r, int x, int y1, LL y2, int k)
{
	if(l == r && l == x){
		q[k] = y1;
		p[k] = y2;
		return ;
	}
	int mid = (l+r)/2;
	if(x <= mid)
		Update(l, mid, x, y1, y2, 2*k);
	else
		Update(mid+1, r, x, y1, y2, 2*k+1);
	pushup(k);
}

int getSum(int l, int r, int al, int ar, int k)
{
	if(l == al && r == ar){
		return q[k];
	}
	int mid = (l+r)/2;
	if(ar <= mid)
		return getSum(l, mid, al, ar, 2*k);
	else if(al > mid)
		return getSum(mid+1, r, al, ar, 2*k+1);
	else{
		return getSum(l, mid, al, mid, 2*k)+
		getSum(mid+1,r, mid+1, ar, 2*k+1);
	}
}

int getId(int l, int r, int x, int k)
{
	if(l == r)return l;
	int mid = (l+r)/2;
	if(x <= q[2*k])
		return getId(l, mid, x, 2*k);
	else
		return getId(mid+1, r, x-q[2*k], 2*k+1);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值