CF1286D LCC
https://www.luogu.com.cn/problem/CF1286D
经典套路题
首先碰撞的一定是相邻两个,然后要么是相遇,要么是追及,
首先把所有可能相遇的情况拿出来,按照发生时间排个序
然后考虑当前情况
i
i
i发生的概率,即前
i
−
1
i-1
i−1个都没有发生
可以用前
i
i
i个没有发生的概率
−
-
−前
i
−
1
i-1
i−1个没有发生的概率得到
对于强制每个相遇不发生,即它的方向被限制了
考虑动态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;
}