Newcoder 143 F.take(线段树)

本文介绍了一种算法问题:给定一系列具有不同概率和价值的盒子,求解在按顺序打开盒子并可能替换手中钻石的过程中,交换次数的期望值。通过使用线段树或树状数组来高效地计算每个元素不出现的概率,最终求得结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

nnn个盒子,第iii个盒子有pip_ipi概率有一个大小为did_idi的钻石,起初有一个大小为000的钻石,之后以此打开111~nnnnnn个盒子,如果打开盒子后发现有一个比手头钻石更大的钻石则换成这个更大的钻石,问交换次数的期望值

Input

第一行一整数TTT表示用例组数,之后nnn行每行输入222个整数pi⋅100,dip_i\cdot 100,d_ipi100,di

(1≤n≤105,1≤pi⋅100≤100,1≤di≤109)(1\le n\le 10^5,1\le p_i\cdot 100\le 100,1\le d_i\le 10^9)(1n105,1pi100100,1di109)

Output

输出交换次数的期望次数,结果模998244353998244353998244353

Sample Input

3
50 1
50 2
50 3

Sample Output

499122178

Solution

期望即为每个值可以被交换的概率,如果aia_iai要被交换,那么aia_iai前面不小于aia_iai的所有元素都不能出现,故从左至右把每个元素不出现的概率插入线段树或者树状数组中(位置为该元素离散化后的编号),每次求和即得到当前元素可以被交换的概率,累加即为结果

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 100005
#define mod 998244353
int Pow(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1)ans=(ll)ans*a%mod;
		a=(ll)a*a%mod;
		b>>=1;
	}
	return ans;
}
int mul(int x,int y)
{
	ll z=1ll*x*y;
	return z-z/mod*mod;
}
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x;
}
int n,p[maxn],q[maxn],a[maxn],h[maxn];
#define ls (t<<1)
#define rs ((t<<1)|1)
int val[maxn<<2];
void push_up(int t)
{
	val[t]=mul(val[ls],val[rs]);
}
void build(int l,int r,int t)
{
	val[t]=1;
	if(l==r)return ;
	int mid=(l+r)/2;
	build(l,mid,ls),build(mid+1,r,rs);
	push_up(t);
}
void update(int x,int l,int r,int t,int v)
{
	if(l==r)
	{
		val[t]=mul(val[t],v);
		return ;
	}
	int mid=(l+r)/2;
	if(x<=mid)update(x,l,mid,ls,v);
	else update(x,mid+1,r,rs,v);
	push_up(t);
}
int query(int L,int R,int l,int r,int t)
{
	if(L<=l&&r<=R)return val[t];
	int mid=(l+r)/2,ans=1;
	if(L<=mid)ans=mul(ans,query(L,R,l,mid,ls));
	if(R>mid)ans=mul(ans,query(L,R,mid+1,r,rs));
	return ans;
}
int main()
{
	scanf("%d",&n);
	int inv=Pow(100,mod-2);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&p[i],&a[i]);
		q[i]=100-p[i];
		h[i-1]=a[i];
		p[i]=mul(p[i],inv);
		q[i]=mul(q[i],inv);
	}
	sort(h,h+n);
	int m=unique(h,h+n)-h,ans=0;
	build(1,m,1);
	for(int i=1;i<=n;i++)
	{
		a[i]=lower_bound(h,h+m,a[i])-h+1;
		ans=add(ans,mul(p[i],query(a[i],m,1,m,1)));
		update(a[i],1,m,1,q[i]);
	}
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值