题目描述
Kanade has n boxes , the i-th box has p[i] probability to have an diamond of d[i] size.
At the beginning , Kanade has a diamond of 0 size. She will open the boxes from 1-st to n-th. When she open a box,if there is a diamond in it and it's bigger than the diamond of her , she will replace it with her diamond.
Now you need to calculate the expect number of replacements.
You only need to output the answer module 998244353.
Notice: If x%998244353=y*d %998244353 ,then we denote that x/y%998244353 =d%998244353
输入描述:
The first line has one integer n.
Then there are n lines. each line has two integers p[i]*100 and d[i].
输出描述:
Output the answer module 998244353
示例1
输入
3
50 1
50 2
50 3
输出
499122178
备注:
1<= n <= 100000
1<=p[i]*100 <=100
1<=d[i]<=10^9
题意:有n个箱子, 每个箱子里面有p[i]/100的概率有一个大小为d[i]的钻石,一开始你手上的钻石大小为0, 你从第一个箱子开始, 依次打开每一个箱子, 如果箱子里面的钻石大小比你手上的大, 那就拿起箱子里的钻石替换自己的, 求最后替换次数的期望。
思路:来自:https://blog.youkuaiyun.com/xiuya19/article/details/81380266
如果直接枚举 交换次数*概率 不仅机器跑步过去,自己的脑子也跑不过去(比赛时自己出的样例算出了3个结果)
实际上,如果我们规定某一颗钻石K是最后的手持的话,那么比它大的钻石盒子就不能开出钻石,
那么显然钻石K对答案的贡献就是打开K的盒子有钻石的概率和打开比他大的盒子但是没钻石的概率。
这样以来实际上顺序开对这种计算方式是没影响的。
这样的话我们对钻石大小从大到小排序,枚举每一颗钻石得到贡献,其和就是答案。
这里可以用树状数组维护前缀积能快速得到比当前钻石大的钻石开不出来的概率乘积。
时间复杂度O(nlogn)
另外有一点要注意的是,因为题目给出的概率是p*100,并且最终结果要取模,因此推荐p用整型保存,计算概率的时候用p*(100的逆元)。
还有就是因为树状数组维护的是前缀积,因此初始化都要变为1.
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
const int mod=998244353;
const int INF=0x3f3f3f3f;
struct point
{
ll p,d,id;
}G[maxn];
long long pow_mod(long long a,long long b,long long m)
{
a=a%m;
long long ans=1;
while(b)
{
if(b&1)
{
ans=(ans*a)%m;
b--;
}
b>>=1;
a=a*a%m;
}
return ans;
}
bool cmp(const point &a,const point &b)
{
if(a.d>b.d)return 1;
else if(a.d==b.d)
{
return a.id<b.id;
}
return 0;
}
ll c[maxn];
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x,ll v)
{
while(x<maxn)
{
c[x]=(c[x]*v)%mod;
x+=lowbit(x);
}
}
ll Sum(int x)
{
ll sum=1;
while(x>0)
{
sum=(sum*c[x])%mod;
x-=lowbit(x);
}
return sum;
}
int main()
{
int n;
scanf("%d",&n);
ll inv=pow_mod(100,mod-2,mod);
for(int i=1;i<=maxn;i++)c[i]=1;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&G[i].p,&G[i].d);
G[i].id=i;
}
sort(G+1,G+1+n,cmp);
ll sum=0;
for(int i=1;i<=n;i++)
{
ll id=G[i].id;
ll p=G[i].p;
ll sum_1=(Sum(id-1)*((inv*p)%mod))%mod;
sum=(sum+sum_1)%mod;
add(id,inv*(100-p)%mod);
}
printf("%lld\n",sum);
return 0;
}
/*
3
50 1
50 2
50 3
*/