1. 程式人生 > >Luogu3600 隨機數生成器

Luogu3600 隨機數生成器

markdown 表示 pla gis cal esp source long 並且

題面

傳送門

Sol

\(sto \ \ \) \(fdf\)
\(sto \ \ \) \(fateice\)

顯然,如果一個區間包含了另一個區間,那麽它的最小值不會有貢獻,直接去掉

考慮枚舉最大值\(k\)
求出所有區間滿足最小值小於等於\(k\)的概率,設為\(P[k]\)
那麽\(k\)的貢獻就是\((P[k]-P[k-1])*k\),相當於差分了一下

然後考慮算出\(P[k]\)
\(f[i]\)表示到\(i\)時,所有右端點都小於等於\(i\)的區間都滿足要求的概率
枚舉右端點在\(i\)的所有左端點\(j\)
枚舉在哪裏弄一個小於等於\(k\)
\[f[i]=\sum_{l=j}^{i}f[l-1]*(\frac{k}{x})*(1-\frac{k}{x})^{i-l}\]

枚舉的這個點之前的隨便選,而後面的只能選大於\(k\)
這樣才能做到不重復計算,因為如果後面的也隨便選,那麽會和之前的有交集
然後這是\(n^3x\)的,居然過了
\(n,x<=2000\)

把上面的轉移式拆一下,把\(f[l-1]*(1-\frac{k}{x})^{-l}\)做個前綴和就好了
特別註意如果\(i=l\)並且\(k=x\)時,\((1-\frac{k}{x})^{i-l}\)要當成\(1\)
那麽特判一下就好了

\(fdf\) $ ??orz$
\(fateice\) $ ??orz$

# include <bits/stdc++.h>
# define RG register
# define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(2005); const int Zsy(666623333); IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-'
? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, x, Q, tp, f[_], g[_], ans, first[_], nxt[_], inv; struct Query{ int l, r; IL int operator <(RG Query B) const{ return l != B.l ? l < B.l : r < B.r; } } tmp[_], q[_]; IL int Pow(RG ll x, RG ll y){ RG ll ret = 1; for(; y; y >>= 1, x = x * x % Zsy) if(y & 1) ret = ret * x % Zsy; return ret; } IL void Upd(RG int &x, RG int y){ x += y; if(x >= Zsy) x -= Zsy; } IL int Sum(RG int l, RG int r){ return (g[r] - (l < 0 ? 0 : g[l]) + Zsy) % Zsy; } IL int Calc(RG int v){ RG int p1 = 1LL * inv * v % Zsy, p2 = (1 + Zsy - p1) % Zsy, p3 = Pow(p2, Zsy - 2); Fill(g, 0), Fill(f, 0), g[0] = p3, f[0] = 1; for(RG int i = 1; i <= n; ++i){ for(RG int p = first[i]; p; p = nxt[p]){ if(i > q[p].l) Upd(f[i], 1LL * Sum(q[p].l - 2, i - 2) * p1 % Zsy * Pow(p2, i) % Zsy); Upd(f[i], 1LL * f[i - 1] * p1 % Zsy); } if(!first[i]) f[i] = f[i - 1]; g[i] = g[i - 1], Upd(g[i], 1LL * f[i] * Pow(p3, i + 1) % Zsy); } return f[n]; } int main(RG int argc, RG char *argv[]){ n = Input(), x = Input(), tp = Input(), inv = Pow(x, Zsy - 2); for(RG int i = 1; i <= tp; ++i) tmp[i] = (Query){Input(), Input()}; sort(tmp + 1, tmp + tp + 1); for(RG int i = 1; i <= tp; ++i){ while(q[Q].r >= tmp[i].r) --Q; if(tmp[i].l > q[Q].l) q[++Q] = tmp[i]; } for(RG int i = 1; i <= Q; ++i) nxt[i] = first[q[i].r], first[q[i].r] = i; for(RG int i = 1, lst = 0; i <= x; ++i){ RG int now = Calc(i); ans = (ans + 1LL * i * ((now - lst + Zsy) % Zsy) % Zsy) % Zsy; lst = now; } printf("%d\n", ans); return 0; }

Luogu3600 隨機數生成器