https://www.nowcoder.com/acm/contest/143/F
题意:给出一条n个节点的路,从1走到n,每个点有一定概率出现一个价值为w的钻石,如果这个钻石比手里的钻石大,他就把之前的扔了选这个。求扔的期望。
分析:
每一个点的扔的概率为,之前比它大的钻石都没有出现的概率。
那么我们就可以通过线段树来维护这个概率,用前缀积实现。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iomanip>
using namespace std;
const int maxn = 1e5 + 12;
#define ll long long int
#define Build build
#define Node node
#define charmax(a,b) a=max(a,b)
#define charmin(a,b) a=min(a,b)
#define clr(a,b) memset(a,b,sizeof a)
#define mod 998244353
#define rmod 828542813
ll a[5*maxn];
//I'm very sorry for my friends and our team "goodbye".That's not my time to say goodbye.I'm back now! ——Irish_Moonshine
struct node {
int x, id, pos;
bool operator < (const node &a) const {
if (x > a.x || x == a.x&&id < a.id) return 1;
return 0;
}
}s[2*maxn];
void Build(int l, int r, int x) {
int m;
if (l == r) { a[x] = 1; return; }
m = (l + r) / 2;
build(l, m, x * 2);
build(m + 1, r, x * 2 + 1);
a[x] = 1;
}
void update(int l, int r, int x, int A, int B) {
int m;
if (l == r) {
a[x] = 1ll * (100 - B)*rmod%mod; return;
}
m = (l + r) / 2;
if (A <= m) update(l, m, x * 2, A, B);
else update(m + 1, r, x * 2 + 1, A, B);
a[x] = a[x * 2] * a[x * 2 + 1] % mod;
}
ll query(int l, int r, int x, int A, int B) {
int m; ll ans = 1;
m = (l + r) / 2;
if (l >= A && r <= B) return a[x];
if (A <= m) ans = ans * query(l, m, x * 2, A, B) % mod;
if (B >= m + 1) ans = ans * query(m + 1, r, x * 2 + 1, A, B) % mod;
return ans;
}
ll qkm(ll a, ll b) {
ll ans = 1;
while(b > 0) {
if (b % 2) ans = ans * a%mod;
a = a * a%mod;
b /= 2;
}
return ans;
}
int main()
{
ll ans=0, n;
scanf("%lld", &n);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &s[i].pos, &s[i].x);
s[i].id = i;
}
sort(s + 1, s + 1 + n);
Build(1, n, 1);
for (int i = 1; i <= n; i++) {
ans = (ans + query(1, n, 1, 1, s[i].id)*s[i].pos%mod*rmod) % mod;
update(1, n, 1, s[i].id, s[i].pos);
}
printf("%lld\n", ans);
return 0;
}