洛谷傳送門
BZOJ傳送門
題目描述
有條南北方向的雙向街道和條東西方向的雙向街道縱橫交錯。相鄰街道(不管是哪個走向)的距離均爲英里。西南角交叉口的座標爲,東北角爲。在所有交叉口均可任意改變行駛方向。每條街道有它自己的最高速度限制,該限制對整條街道有效(不管行駛方向如何)。
你的任務是從交叉口開車行駛到,要求只能在交叉口處改變速度,行駛過程中不得違反所在街道的速度限制,只能沿着路程最短的線路行駛,並且行駛時間在給定的閉區間內。車速以“每小時英里數”爲單位,它必須是的正整數倍。若車速爲,則每加侖汽油能行駛的英里數爲。
輸入輸出格式
輸入格式:
輸入第一行爲兩個整數。
第二行包含個正整數,從南到北描述條東西走向的街道的速度限制。
第三行包含個正整數,從西到東描述條南北走向的街道的速度限制。
第四行包含六個正整數。
輸出格式:
如果無解,輸出No
。
否則輸出兩行,分別描述最早到達的方案(若有多種方案,選擇其中最省油的)和最省油的方案(如果有多種方案,選擇其中最早到達的)。每種方案用兩個數表示,第一個數表示到達時刻(單位:分鐘,向上取整);第二個數表示耗油量(單位:加侖,四捨五入保留兩位小數)。
輸入輸出樣例
輸入樣例#1:
6 20
30 40 50 50 50 50
50 50 50 50 50 40
1 1 6 6 300 320
輸出樣例#1:
300 6.25
318 5.60
輸入樣例#2:
8 2
10 20 20 30 10 20 10 10
10 20 20 30 10 20 10 20
6 8 2 4 10 39
輸出樣例#2:
No
說明
樣例的最快路線爲以英里/小時爲速度勻速前進,路程爲英里,因此時間爲小時,每加侖汽油可以行駛英里,因此耗油量爲加侖。
最省油路線是先以英里/小時行駛英里,然後以英里/小時行駛英里,耗油量爲加侖。下圖的路線可以同時滿足兩種方案(其中第二種方案需要在處改變速度)。
20%的數據滿足:
50%的數據滿足:
100%的數據滿足:. 速度限制不超過
解題分析
思路很妙妙的。
很容易看出, 如果我們設爲在方向走了步, 在方向走了步, 油量或時間用了的最優時間/油量, 都可以轉移,問題在於是一個實數, 無法記錄這一維狀態。
考慮轉化一下時間: 我們要求先把速度, 使速度變爲的正整數, 最後把時間就可以轉化回來了。 然後我們想記錄的時間實際上是, 先統一乘一個 ,就可以轉化爲一個整數的狀態, 最後再除回來就好了。
注意題目問的是分鐘, 給的是小時, 乘上60。
總複雜度。
代碼如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define EPS 1e-8
#define INF 1e20
#define gc getchar()
#define ll long long
#define db double
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
const int LCM = 2520;
const int UP = 2 * 10 * LCM;
int n, L, t1, t2;
int dx, dy, sx, sy, tx, ty, delx, dely;
int limx[15], limy[15], tcost[15];
db dp[11][11][UP + 1];
IN db calc(R int v) {return 80 - 0.03 * v * v;}
int main(void)
{
R int i, j, k, v, cx, cy, nxx, nxy;
scanf("%d%d", &n, &L);
for (i = 0; i < n; ++i) scanf("%d", &limx[i]);//lr
for (i = 0; i < n; ++i) scanf("%d", &limy[i]);//ud
scanf("%d%d%d%d%d%d", &sx, &sy, &tx, &ty, &t1, &t2);
sx--, sy--, tx--, ty--;
delx = abs(tx - sx), dely = abs(ty - sy);
dx = tx - sx < 0 ? -1 : 1, dy = ty - sy < 0 ? -1 : 1;
for (R int i = 1; i <= 10; ++i) tcost[i] = LCM / i;
for (i = 0; i <= delx; ++i)
for (j = 0; j <= dely; ++j)
for (k = 0; k <= UP; ++k)
dp[i][j][k] = INF;
dp[0][0][0] = 0;
for (i = 0; i <= delx; ++i)
for (j = 0; j <= dely; ++j)
for (k = 0; k <= UP; ++k) if (dp[i][j][k] < INF)
{
cx = i + 1, cy = j;
if (cx <= delx)
{
nxx = sx + cx * dx, nxy = sy + cy * dy;
for (v = 1; v * 5 <= limx[nxy] && tcost[v] + k <= UP; ++v)
dp[cx][cy][tcost[v] + k] = min(dp[cx][cy][tcost[v] + k], dp[i][j][k] + 1.0 * L / calc(5 * v));
}
cx = i, cy = j + 1;
if (cy <= dely)
{
nxx = sx + cx * dx, nxy = sy + cy * dy;
for (v = 1; v * 5 <= limy[nxx] && tcost[v] + k <= UP; ++v)
dp[cx][cy][tcost[v] + k] = min(dp[cx][cy][tcost[v] + k], dp[i][j][k] + 1.0 * L / calc(5 * v));
}
}
int mntim = -1, mnoil = -1;
for (i = 0; i <= UP; ++i) if (dp[delx][dely][i] != INF)
{
db tim = 1.0 * i * L * 12 / LCM;
if (tim >= t1 && tim <= t2)
{
if (mntim == -1) mntim = i;
if (mnoil == -1) mnoil = i;
else if (dp[delx][dely][i] < dp[delx][dely][mnoil]) mnoil = i;
}
}
if (mntim == -1) return puts("No"), 0;
printf("%d %.2lf\n", (int)std::ceil(1.0 * mntim * L * 12 / LCM), dp[delx][dely][mntim]);
printf("%d %.2lf\n", (int)std::ceil(1.0 * mnoil * L * 12 / LCM), dp[delx][dely][mnoil]);
}