UOJ #514 [UR #19]通用测评号 (容斥原理、DP)
題目鏈接
http://uoj.ac/contest/51/problem/514
題解
神仙們都好強(qiáng)啊。
本題有好多做法,但是第一步都是一樣的:
題目中的“每次選一個(gè)沒有達(dá)到 \(a\) 的進(jìn)行裝填”其實(shí)沒有用,可以等價(jià)成每次隨機(jī)選任何一個(gè)位置 \(+1\),然后求 \(\ge a\) 的個(gè)數(shù)的期望。
然后考慮計(jì)算 \(1\) 號(hào)位置最后達(dá)到 \(a\) 了的概率。
不容斥做法
考慮操作序列,對(duì)每個(gè)位置 \(+1\) 視為一種不同的操作。我們將一種非 \(1\) 操作的次數(shù)達(dá)到 \(b\) 或者 \(1\) 操作達(dá)到 \(a\) 稱為“終止”。一種操作終止之后,我們忽略這種操作,不再加入進(jìn)操作序列中。于是操作序列的總長(zhǎng)是 \((n-1)b+a\).
考慮計(jì)算最后一次為 \(1\) 操作的概率。那么也就是說剩下 \((n-1)\) 種操作要在之前全部終止。設(shè)終止的時(shí)間從小到大排序?yàn)?\(t_1,t_2,...,t_{n-1}\),那么容易得到概率為
直接對(duì)這個(gè)東西做一個(gè) DP,設(shè) \(f[i][j]\) 表示目前操作序列放了 \(i\) 個(gè)元素,已經(jīng)有 \(j\) 種操作終止了。
時(shí)間復(fù)雜度 \(O(n^3)\).
容斥做法
容斥。考慮枚舉 \(1\) 號(hào)位置達(dá)到 \(a\) 時(shí)沒有達(dá)到 \(b\) 的位置個(gè)數(shù) \(i\). 那么別的位置照樣可以不考慮。
假設(shè)欽定了 \(k\) 個(gè)位置,連帶著 \(1\) 實(shí)際被操作的次數(shù)分別記為 \(x_i\),其中 \(1\) 的次數(shù)記作 \(x_0\),則 \(\forall 1\le i\le k,0\le x_i\le b-1\). 考慮計(jì)算當(dāng) \(x_0=a-1\) 的時(shí)候,出現(xiàn)每個(gè)局面的概率之和,再乘以下一步操作 \(1\) 的概率 \(\frac{1}{k}\). 則對(duì)于一組合法的 \(x_0=a-1,x_1,...,x_k\),概率為
對(duì)所有欽定方案的所有 \(b\) 序列求和,直接 DP 可以做到 \(O(n^4)\),NTT 優(yōu)化可以做到 \(O(n^3\log n)\).
有一個(gè)神奇的優(yōu)化:發(fā)現(xiàn)我們就是要求一個(gè)生成函數(shù) \(F(x)\sum^{b-1}_{i=0}\frac{x^i}{i!}\) 的 \(0,1,...,n\) 次冪的每一項(xiàng)系數(shù)。而這種長(zhǎng)得很像 \(e^x\) 的函數(shù),求導(dǎo)往往有奇效:
\[(F(x)^i)'=iF(x)^{i-1}F'(x)=iF(x)^i-iF(x)^{i-1}\cdot \frac{x^{b-1}}{(b-1)!} \]這個(gè)式子可以一項(xiàng)一項(xiàng)地推出來系數(shù),時(shí)間復(fù)雜度 \(O(n^3)\).
然后還有一種神奇的 DP,大概是從前往后考慮操作序列,減掉當(dāng)前這個(gè)數(shù)出現(xiàn)次數(shù) \(\ge b\) 的情況。時(shí)間復(fù)雜度 \(O(n^3)\).
代碼
不容斥做法
#include<bits/stdc++.h> #define llong long long #define mkpr make_pair #define x first #define y second #define iter iterator #define riter reversed_iterator #define y1 Lorem_ipsum_dolor using namespace std;inline int read() {int x = 0,f = 1; char ch = getchar();for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}return x*f; }const int mxN = 250; const int P = 998244353;void updsum(llong &x,llong y) {x+=y-P,x+=(x>>31)&P;}llong quickpow(llong x,llong y) {if(y==0) {return 1ll;}llong ret = quickpow(x,y>>1); ret = ret*ret%P; if(y&1ll) {ret = ret*x%P;}return ret; } llong fact[mxN*mxN+3],facti[mxN*mxN+3],inv[mxN*mxN+3]; void initfact(int n) {fact[0] = 1ll; for(int i=1; i<=n; i++) fact[i] = fact[i-1]*i%P;facti[n] = quickpow(fact[n],P-2); for(int i=n-1; i>=0; i--) facti[i] = facti[i+1]*(i+1ll)%P;for(int i=1; i<=n; i++) inv[i] = facti[i]*fact[i-1]%P; } llong comb(llong x,llong y) {return x<0||y<0||x<y?0ll:fact[x]*facti[y]%P*facti[x-y]%P;}llong f[mxN*mxN+3][mxN+3]; int n,a,b; llong ans;int main() {initfact(mxN*mxN);n = read(),a = read(),b = read();f[0][0] = 1ll;for(int i=0; i<=(n-1)*b+a-1; i++){for(int j=0; j<=n-1&&j*b<=i; j++){llong x = f[i][j]; if(!x) continue; // printf("f[%d][%d]=%lld\n",i,j,x);x = x*inv[n-j]%P;updsum(f[i+1][j],x);updsum(f[i+1][j+1],x*comb(i-j*b,b-1)%P);}}ans = f[(n-1)*b+a-1][n-1];ans = (1ll-ans*fact[n-1]%P+P)*n%P;printf("%lld\n",ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的UOJ #514 [UR #19]通用测评号 (容斥原理、DP)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UOJ #513 [UR #19]清扫银
- 下一篇: Codeforces 1338E JYP