題解 「BJOI2018 治療之雨」
阿新 • • 發佈:2020-09-09
題目大意
有一個初始為 \(p\) 的數,每次操作分為以下兩個:
-
有 \(\frac{1}{m+1}\) 的概率$+1,但是中途 \(p\) 的最大值只能為 \(n\)$
-
有 \(k\) 次減少操作,每次有 \(\frac{1}{m+1}\) 的概率 \(-1\)。
(每次先操作操作 \(1\) 然後操作操作 \(2\))
問 \(p\) 變為 \(0\) 的期望操作次數。
有 \(T\) 次詢問,每次保證 \(1\le p\le n\le 1500,m,k\le 10^9\),答案對 \(10^9+7\) 取模。
思路
其實這道題很水,也不知道怎麼評到黑題的。
首先,我們可以發現,\(k\)
然後我們發現肯定可以設 \(f_i\) 表示當前值為 \(i\) 的剩餘期望操作次數,我們可以得到轉移式:
\[f_i=\sum_{j=0}^{i+1}p_{i,j}\times f_j+1 \]
\[\Rightarrow f_{i+1}=\frac{1}{p_{i,i+1}}(f_i-1-\sum_{j=0}^{i}p_{i,j}\times f_j) \]
然後你發現這個東西可以用一個套路做了,就是說我們發現每一個 \(f_i\)
時間複雜度 \(\Theta(Tn\log n)\)。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 1000000007 #define MAXN 1505 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a); return res; } int inv (int x){return qkpow (x,mod - 2);} int n,m,k,st,invx,invm,ci[MAXN],binom[MAXN]; int calc (int x){//計算k輪中減少x的概率 if (x < 0 || x > k) return 0; else return mul (binom[x],mul (ci[x],invx)); } int pro (int i,int j){ if (i == n) return calc (i - j); else return add (mul (calc (i - j),dec (1,invm)),mul (calc (i - j + 1),invm)); } struct node{ int k,b;//表示為k*f[1]+b node (){} node (int _k,int _b){k = _k,b = _b;} node operator + (int x){return node (k,add (b,x));} node operator - (int x){return node (k,dec (b,x));} node operator * (int x){return node (mul (k,x),mul (b,x));} node operator + (node x){return node (add (k,x.k),add (b,x.b));} node operator - (node x){return node (dec (k,x.k),dec (b,x.b));} }f[MAXN]; signed main(){ int T;read (T); while (T --> 0){ read (n,st,m,k),invx = inv (qkpow (m + 1,k)),invm = inv (m + 1); if (!k){puts ("-1");continue;} if (!m){ if (k == 1) puts ("-1"); else{ int cnt = 0; while (st > 0) cnt ++,st = min (n,st + 1) - k; write (cnt),putchar ('\n'); } continue; } binom[0] = 1;for (Int i = 1;i <= n;++ i) binom[i] = mul (binom[i - 1],mul (k - i + 1,inv (i))); for (Int i = 0;i <= n && i <= k;++ i) ci[i] = qkpow (m,k - i); f[1] = node (1,0); for (Int i = 1;i <= n - 1;++ i){ f[i + 1] = node (0,0); for (Int j = 1;j <= i;++ j) f[i + 1] = f[i + 1] + f[j] * pro (i,j); f[i + 1] = (f[i] - 1 - f[i + 1]) * inv (pro (i,i + 1)); } node sum = node (0,0); for (Int i = 1;i <= n;++ i) sum = sum + f[i] * pro (n,i); sum = f[n] - 1 - sum;int f1 = mul (mod - sum.b,inv (sum.k)); write (add (f[st].b,mul (f1,f[st].k))),putchar ('\n'); } return 0; }