注意到速度的形式是编号相乘,而又有 \(x \in \{1, 2, 3, 4\}\),所以最多 \(\log_2y_i\) 次速度就会达到 \(10^9\) 量级,而此时再加油最少需要 \(1\) 秒,所以再乘一定不优。
直接 dp,有 \(f_{i, j, k}\) 表示当前在第 \(i\) 个加油站,速度为 \(2^j3^k\) 的最短用时,后面的 \(2^j3^k\) 可以递推处理。
具体的,转移考虑当前加油站是否加油即可。
对于询问,二分出当前位置前面的第一个加油站,然后枚举终点状态计算答案即可。
复杂度 \(O(n\log_2y\log_3y + q\log_2 y\log_3y)\)。
// 如果命运对你缄默, 那就活给他看。
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <cfloat>
#include <iostream>
#include <cstring>
#include <tuple>
#include <iomanip>
#include <cassert>
using namespace std;
typedef long long LL;
// typedef long double LD;
typedef double LD;
// #define int LL
const int maxn = 100010;
inline LD cmi(LD& x, LD y) { if(y < x) x = y; return x; }
struct Port {
int p, t, x;
Port () {}
Port (int a, int b, int c) { p = a, t = b, x = c; }
} w[maxn];
int n, q;
LL ve[31][20];
LD f[maxn][31][20];
inline int Bound(int y) {
int l = 0, r = n;
while(l < r) {
int mid = l + r + 1 >> 1;
if(w[mid].p <= y) l = mid;
else r = mid - 1;
} return l;
}
signed main() {
// freopen("ship2.in", "r", stdin);
// freopen("ship.out", "w", stdout);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; ++ i) {
int p, t, x;
cin >> p >> t >> x;
w[i] = {p, t, x};
}
ve[0][0] = 1;
for(int j = 1; j < 20; ++ j) ve[0][j] = ve[0][j - 1] * 3;
for(int i = 1; i <= 30; ++ i) {
ve[i][0] = ve[i - 1][0] * 2;
for(int j = 1; j < 20; ++ j) {
ve[i][j] = ve[i][j - 1] * 3;
}
}
for(int i = 0; i <= n; ++ i) {
for(int j = 0; j <= 30; ++ j) {
for(int k = 0; k < 20; ++ k) {
f[i][j][k] = 1e18;
}
}
}
f[0][0][0] = 0;
for(int i = 1; i <= n; ++ i) {
auto [p, t, x] = w[i];
for(int j = 0; j <= 30; ++ j) {
for(int k = 0; k < 20; ++ k) {
cmi(f[i][j][k], f[i - 1][j][k] + 1.0 * (w[i].p - w[i - 1].p) / ve[j][k]);
int j2 = j, k2 = k;
if(x == 2) j2 -- ;
else if(x == 3) k2 -- ;
else if(x == 4) j2 -= 2;
if(j2 < 0 || k2 < 0) continue ;
LL v = ve[j2][k2];
LD nt = 1.0 * (w[i].p - w[i - 1].p) / v;
cmi(f[i][j][k], f[i - 1][j2][k2] + t + nt);
}
}
}
for(int y; q -- ; ) {
cin >> y;
LD ans = DBL_MAX;
int x = Bound(y);
for(int i = 0; i <= 30; ++ i) {
for(int j = 0; j < 20; ++ j) {
LL v = ve[i][j];
LD nt = 1.0 * (y - w[x].p) / v;
cmi(ans, f[x][i][j] + nt);
}
}
cout << fixed << setprecision(7) << ans << '\n';
}
return 0;
}
调的时候挂在了奇妙的地方:memset
一个 long double
数组 \(0x7f\) 会出来 nan /hsh。