CF1286D LCC

https://www.luogu.com.cn/problem/CF1286D

经典套路题

首先碰撞的一定是相邻两个,然后要么是相遇,要么是追及,

首先把所有可能相遇的情况拿出来,按照发生时间排个序

然后考虑当前情况 i i i发生的概率,即前 i − 1 i-1 i1个都没有发生
可以用前 i i i个没有发生的概率 − - i − 1 i-1 i1个没有发生的概率得到

对于强制每个相遇不发生,即它的方向被限制了

考虑动态DP维护
f [ r t ] [ 0 / 1 ] [ 0 / 1 ] f[rt][0/1][0/1] f[rt][0/1][0/1]表示rt对应的区间,左右端点的小球方向是 左 / 右 左/右 /的概率
合并的时候只需看看 m i d mid mid m i d + 1 mid+1 mid+1小球的方向转移即可(类似矩阵,但不完全一样)

看代码加速理解
code:


#include<bits/stdc++.h>
#define mod 998244353
#define ll long long
#define N 200050
#define ls (rt << 1)
#define rs (rt << 1 | 1)
using namespace std;
ll qpow(ll x, ll y) {
    ll ret = 1;
    for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
    return ret;
}
ll s[N << 2][2][2];
int limit[N][2][2], p[N], x[N], v[N], gs, py[N], pyy[N << 2];
void update(int rt, int mid) {
    for(int i = 0; i <= 1; i ++) 
        for(int j = 0; j <= 1; j ++) {
            s[rt][i][j] = 0;
            for(int x = 0; x <= 1; x ++)
                for(int y = 0; y <= 1; y ++)
                    if(!limit[mid][x][y]) {
                        s[rt][i][j] += s[ls][i][x] * s[rs][y][j];
                        s[rt][i][j] %= mod;
                    }
        }
}
void build(int rt, int l, int r) {
    if(l == r) {
        s[rt][1][1] = p[l];
        s[rt][0][0] = (1 + mod - p[l]) % mod;
        return ;
    }
    int mid = (l + r) >> 1;
    py[mid] = rt, pyy[rt] = mid;
    build(ls, l, mid), build(rs, mid + 1, r);
    update(rt, mid);
}
struct Q {
    int x, o, oo, s, t;
} b[N << 2];
int cmp(Q x, Q y) {
    return 1ll * x.s * y.t < 1ll * y.s * x.t;
}
int n;
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) {
        scanf("%d%d%d", &x[i], &v[i], &p[i]);
        p[i] = p[i] * qpow(100, mod - 2) % mod;
    }
    for(int i = 1; i < n; i ++) {
        b[++ gs] = (Q){i, 1, 0, x[i + 1] - x[i], v[i] + v[i + 1]};
        if(v[i] > v[i + 1]) b[++ gs] = (Q){i, 1, 1, x[i + 1] - x[i], v[i] - v[i + 1]};
        if(v[i] < v[i + 1]) b[++ gs] = (Q){i, 0, 0, x[i + 1] - x[i], v[i + 1] - v[i]};
    }
    sort(b + 1, b + 1 + gs, cmp);
    build(1, 1, n);
    ll ans = 0, lst = 1;
    for(int i = 1; i <= gs; i ++) {
        limit[b[i].x][b[i].o][b[i].oo] = 1;
     //   printf("%d %d %d %d %d\n", b[i].x, b[i].o, b[i].oo, b[i].s, b[i].t);
        int x = py[b[i].x];
        while(x) {
            update(x, pyy[x]), x >>= 1;
        }

        ll now = (s[1][0][0] + s[1][0][1] + s[1][1][0] + s[1][1][1]) % mod;
        ans += b[i].s * qpow(b[i].t, mod - 2) % mod * (lst - now + mod) % mod;
        ans %= mod; lst = now;
    }    
    printf("%lld", ans);
    return 0;
}
posted @ 2021-10-29 08:48  lahlah  阅读(31)  评论(0编辑  收藏  举报