CF 553E Kyoya and Train
阿新 • • 發佈:2021-01-20
- \(n\le 55\) 個點, \(m \le 100\) 條邊的有向圖,每條邊有代價 \(c\),且花費的時間為 \(1...t\) 的概率是給定的,若從 \(1\) 到 \(n\) 的總時間超過了 \(t\),則還需付出 \(x\) 的代價,求出決策最優時的期望代價。
考慮 \(dp\),設 \(f_{u,i}\) 為當前在 \(u\),時間為 \(i\),最少還需要付出代價的期望。
\[f_{u,j} = \min \limits_{v} \sum_{k = 1}^t f_{v,j + k}*p_{{u,v},k} + w \]\(i > t\) 時,\(f_{u, i} = d_{i, n} + x\)
考慮每條邊對 \(f\) 的貢獻,發現把 \(p\) 翻轉以後是卷積的形式,所以可以分治 \(FFT\) 優化這個過程。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define per(i, a, b) for (int i = (a); i >= (b); i--) #define fi first #define se second typedef long long LL; typedef pair <int, int> P; const int inf = 0x3f3f3f3f, mod = 1e9 + 7, N = 4e4 + 5; template <typename T> inline void rd_(T &x) { x = 0; int f = 1; char ch = getchar(); while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') x = x*10 + ch - '0', ch = getchar(); x *= f; } struct C { double x, y; C (double a = 0, double b = 0) { x = a, y = b; } } A[N], B[N]; C operator + (C a, C b) { return C(a.x + b.x, a.y + b.y); } C operator - (C a, C b) { return C(a.x - b.x, a.y - b.y); } C operator * (C a, C b) { return C(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x); } int n, m, t, x, d[55][55], a[105], b[105], c[105], len, cnt, rev[N]; double p[101][N], f[55][N], g[105][N], Pi = acos(-1); void fft_(C *a, int f) { rep (i, 0, len - 1) if (i < rev[i]) swap(a[i], a[rev[i]]); for (int s = 2; s <= len; s <<= 1) { C wn(cos(2*Pi/s), f*sin(2*Pi/s)); for (int j = 0; j < len; j += s) { C w(1, 0); for (int k = 0; k < s/2; k++, w = w*wn) { C u = a[j + k], v = a[j + k + s/2]*w; a[j + k] = u + v, a[j + k + s/2] = u - v; } } } if (f == -1) rep (i, 0, len - 1) a[i].x /= len; } void calc_(int x, int l, int r) { int mid = (l + r)>>1; for (len = 1, cnt = 0; len <= r - mid - 1 + r - l; len <<= 1) cnt++; rep (i, 0, len - 1) rev[i] = (rev[i>>1]>>1) + ((i&1)<<cnt - 1), A[i] = B[i] = (C) {0, 0}; rep (i, 0, r - l - 1) A[i].x = p[x][i + 1]; per (i, r, mid + 1) B[r - i].x = f[b[x]][i]; fft_(A, 1), fft_(B, 1); rep (i, 0, len - 1) A[i] = A[i]*B[i]; fft_(A, -1); rep (i, l, mid) g[x][i] += A[r - i - 1].x; } void solve_(int l, int r) { if (l >= t) return; if (l == r) { rep (i, 1, n - 1) f[i][l] = inf; rep (i, 1, m) f[a[i]][l] = min(f[a[i]][l], g[i][l] + c[i]); return; } int mid = (l + r)>>1; solve_(mid + 1, r); rep (i, 1, m) calc_(i, l, r); solve_(l, mid); } int main() { rd_(n), rd_(m), rd_(t), rd_(x); memset(d, 0x3f, sizeof(d)); rep (i, 1, n) d[i][i] = 0; rep (i, 1, m) { rd_(a[i]), rd_(b[i]), rd_(c[i]); rep (j, 1, t) rd_(p[i][j]), p[i][j] /= 100000.0; d[a[i]][b[i]] = min(d[a[i]][b[i]], c[i]); } rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); rep (i, 0, 2*t - 1) f[n][i] = (i > t)*x; rep (i, 1, n - 1) rep (j, t, 2*t - 1) f[i][j] = d[i][n] + x; solve_(0, 2*t - 1); return printf("%.7f\n", f[1][0]), 0; }