[BZOJ5292][Bjoi2018]治療之雨(期望DP+高斯消元)
阿新 • • 發佈:2018-12-16
Address
Solution
首先,一個顯然的 DP 狀態: 表示第一個數當前為 ,將其變成 的期望步數。 邊界當然是 。 討論一波轉移: 設 表示當第一個數為 時, 輪減操作讓第一個數減少 的概率。 這樣轉移就很顯然了: 當 時: 當 時: 要解決兩個小問題: (1) 的值。 分下類: 當 時,相當於在 次操作中選出 次操作對第一個數進行,剩下的 次操作對剩下的 個數進行。 所以: 特別地,如果 則 。 (2) 轉移的後效性。 把每個 當作一個未知變數,使用高斯消元解方程。 但這樣複雜度是 的。 發現係數矩陣長這個樣子: 從第一列到第 列分別表示 到 ,第一行到第 行分別表示 和 的轉移。 這矩陣已經非常接近於下三角矩陣。 我們只需要從最後一行開始網上,對於第 ( )行,只需要用第 行去消第 行使得第 行第 列為 即可。 這樣係數矩陣就變成了下三角矩陣,從 開始一一代入即可。 注:如果出現了除以 的情況則方程組無解,輸出 。 時間複雜度 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
template <class T>
T Min(T a, T b) {return a < b ? a : b;}
const int N = 1505, ZZQ = 1e9 + 7;
int n, p, m, k, inv[N], f[N][N], pw[N], C[N], a[N];
int qpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1ll * res * a % ZZQ;
a = 1ll * a * a % ZZQ;
b >>= 1;
}
return res;
}
void work()
{
int i, j, alls, orz, tmp, rp;
n = read(); p = read(); m = read(); k = read();
orz = qpow(m + 1, ZZQ - 2);
alls = qpow(qpow(m + 1, k)