牛客網暑期ACM多校訓練營(第五場)F take【線段樹】
阿新 • • 發佈:2018-12-24
題意:給出一條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;
}