时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
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个盒子,每一个盒子i有p[i]的概率开出d[i]大的钻石
现在Kanadeyic手持大小为0的钻石,依次从1~n打开箱子,如果箱子内的钻石比手中的大时就交换。
求交换次数的期望。
思路:
如果直接枚举 交换次数*概率 不仅机器跑步过去,自己的脑子也跑不过去(比赛时自己出的样例算出了3个结果)
实际上,如果我们规定某一颗钻石K是最后的手持的话,那么比它大的钻石盒子就不能开出钻石,
那么显然钻石K对答案的贡献就是打开K的盒子有钻石的概率和打开比他大的盒子但是没钻石的概率。
这样以来实际上顺序开对这种计算方式是没影响的。
这样的话我们对钻石大小从大到小排序,枚举每一颗钻石得到贡献,其和就是答案。
这里可以用树状数组维护前缀积能快速得到比当前钻石大的钻石开不出来的概率乘积。
时间复杂度O(nlogn)
另外有一点要注意的是,因为题目给出的概率是p*100,并且最终结果要取模,因此推荐p用整型保存,计算概率的时候用p*(100的逆元)。
还有就是因为树状数组维护的是前缀积,因此初始化都要变为1.
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include<iomanip>
#include<bitset>
#define lson l,m
#define rson m+1,r
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = int(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = 998244353;
const double eps = 1e-8;
struct nodes {
LL p, d;
int id;
bool operator < (const nodes&a)const {
if (d == a.d) return id < a.id;
return d > a.d;
}
}num[maxn];
LL tc[maxn];
int lowbit(int x) {
return x & (-x);
}
void add(int x, LL d) {
for (int i = x; i < maxn; i += lowbit(i))
tc[i] = (tc[i] * d) % mod;
}
LL query(int x) {
LL sum = 1;
for (int i = x; i > 0; i -= lowbit(i))
sum = (sum*tc[i]) % mod;
return sum;
}
int main() {
//ios::sync_with_stdio(false);
//cin.tie(0);
//freopen("D:\\cpp\\test.txt", "r", stdin);
//freopen("D:\\cpp\\\comper\\8.in", "w", stdout);
int n;
LL inv = 828542813;
scanf("%d", &n);
for (int i = 0; i < maxn - 10; i++)
tc[i] = 1;
for (int i = 0; i < n; i++) {
scanf("%lld%lld", &num[i].p, &num[i].d);
num[i].id = i + 1;
}
sort(num, num + n);
LL ans = 0;
for (int i = 0; i < n; i++) {
LL tmp = num[i].p*inv%mod*query(num[i].id - 1) % mod;
ans = (ans + tmp) % mod;
add(num[i].id, (100 - num[i].p)*inv%mod);
}
printf("%lld\n", ans);
return 0;
}