總共有\(n\)種物品,每秒等機率拿到其中一種,第\(i\)秒要花費\(i^k\)的費用,問集齊\(n\)種物品花費的指望值,對\(998244353\)取模(本題內約定\(0^0=1\))ios
數據範圍:\(1\leq n,k\leq 100\)c++
*爲了不混淆,如下用大寫\(K\)表示題目中的\(k\)spa
一個前置技能:\((x+1)^k=\sum\limits_{i}\binom k i x^i\)code
而後考慮dp,設\(f[i][j]\)表示集齊\(i\)種物品的、計算花費的指數爲\(j\)的指望花費,那麼多拿一個物品有兩種不一樣的狀況:(1)拿到一個已經拿過的物品,機率爲\(\frac{i}{n}\);(2)拿到一個新物品,機率爲\((1-\frac{i}{n}\))ip
而後咱們還要考慮上多拿的這個物品帶來的花費string
然而如今的問題是咱們並不知道轉移過來的狀態裏面已通過去了多少秒,因此沒法直接得出花費it
(如下是感性理解時間qwq不必定對。。)io
這個時候考慮一下\(f\)自己的含義,由於它是指望,也就是形如\(P_1\cdot (1^k)+P_2\cdot(1^k+2^k)+P_3\cdot(1^k+2^k+3^k)+...+P_m\cdot(1^k+2^k+3^k+...+m^k)\),其中\(\sum\limits_{i} P_i=1\)class
那麼新加了一個物品以後咱們想要獲得的應該是\(P_1\cdot(1^k+2^k)+P_2\cdot(1^k+2^k+3^k)+...\)這樣,這個時候就能夠用前置技能的那條式子了:
\[ f'[i][j]=\frac{i}{n}\sum\limits_{k}\binom j k f[i][k]+(1-\frac{i}{n})\sum\limits_{k}\binom j k f[i-1][k] \]
然而實際上這個獲得的並非真正的\(f[i][j]\),由於注意到用上面那條式子偏移以後咱們獲得的是\(P_1\cdot (2^k)+P_2\cdot (2^k+3^k)+...\)這樣的東西,每項裏面都少了一個\(1^k\)stream
因此這個時候咱們能夠將原來的\(P_1\cdot (1^k)+P_2\cdot(1^k+2^k)+...\)每項加上一個\(0^k\)獲得\(P_1\cdot (0^k+1^k)+P_2\cdot (0^k+1^k+2^k)+...\)這樣的式子,而後再進行偏移就是咱們要的形式了,而這樣操做其實就是至關於在轉移的時候給\(f[i][k]\)和\(f[i-1][k]\)分別加上一個\(0^k\)(由於\(\sum P_i=1\)提出來就是\(0^k\)了)
因此真正的轉移應該是:
\[ f[i][j]=\frac{i}{n}\sum\limits_{k}\binom j k (f[i][k]+0^k)+(1-\frac{i}{n})\sum\limits_{k}\binom j k (f[i-1][k]+0^k) \]
由於\(k\)是從\(0\)開始枚舉的,\(0^0=1\),其餘都是\(0\),因此其實就是至關於上面那個假轉移式加上\(1\)
而後把右邊的\(f[i][k](k=j)\)這項移到左邊去搞一搞就行了
小細節:由於當\(i=n\)的時候\(n-i=0\),而後就會出如今移完項以後的式子裏面分母爲\(0\)的狀況,因此這條轉移是不能計算\(f[n]\)的,由於一旦集齊就不須要再進行操做,因此\(f[n][K]\)只能從\(f[n-1][K]\)轉移過來,因此就是一樣的用上面的式子偏移一下獲得\(\sum\limits_{i}\binom K i(f[n-1][i]+0^i)\)就是答案了
時間複雜度\(O(n^3)\)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=110,MOD=998244353; int fac[N],invfac[N],inv[N]; int f[N][N]; int n,K; int mul(int x,int y){return 1LL*x*y%MOD;} int plu(int x,int y){return (1LL*x+y)-(1LL*x+y>=MOD?MOD:0);} int C(int n,int m){return n<m?0:mul(fac[n],mul(invfac[m],invfac[n-m]));} int ksm(int x,int y){ int ret=1,base=x; for (;y;y>>=1,base=mul(base,base)) if (y&1) ret=mul(ret,base); return ret; } void prework(int n){ fac[0]=1; for (int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i); invfac[n]=ksm(fac[n],MOD-2); for (int i=n-1;i>=0;--i) invfac[i]=mul(invfac[i+1],i+1); inv[0]=inv[1]=1; for (int i=2;i<=n;++i) inv[i]=mul(MOD-MOD/i,inv[MOD%i]); } void solve(){ int tmp1,tmp2,p1,p2; int tmp; f[1][0]=mul(n,inv[n-1]); for (int i=1;i<n;++i) for (int j=0;j<=K;++j){ if (i==1&&j==0) continue; tmp1=tmp2=0; for (int k=0;k<=j;++k){ if (k<j) tmp1=plu(tmp1,mul(C(j,k),f[i][k])); tmp2=plu(tmp2,mul(C(j,k),f[i-1][k])); } p1=mul(i,inv[n]); p2=plu(1,MOD-p1); f[i][j]=plu(mul(p1,tmp1),plu(mul(p2,tmp2),1)); tmp=mul(n,inv[n-i]); f[i][j]=mul(f[i][j],tmp); } int ans=0; for (int i=0;i<=K;++i) ans=plu(ans,mul(C(K,i),f[n-1][i])); ans=plu(ans,1); printf("%d\n",ans); } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif scanf("%d%d",&n,&K); prework(max(n,K)); solve(); }