B. 艱難睡眠
題目描述
一天有 \(M\) 分鐘,依次編號 \(1,2,\dots,M\)。有 \(N\) 個人,第 \(i\) 個人會在 \(A_i\) 分鐘開始吵鬧,持續 \(B_i\) 分鐘(可能會到第二天)。現在你想要睡連續 \(k\) 分鐘,所以你要使得這 \(k\) 分鐘內沒人吵鬧。你可以花費 \(c_{i,j}\) 的代價讓第 \(i\) 個人從 \(j\) 分鐘開始吵鬧。求你至少需要多少代價才能睡覺,或者確定你不能睡覺。
思路
顯然只有存在 \(B_i>M-k\) 時,你才不能睡覺。
首先列舉在什麼時候睡覺,我們可以對於每個人求出他在什麼時間段不會吵到睡覺,使用 st 表求出這個時間段內的最小需要代價即可。
時空複雜度均為 \(O(NM\log M)\)。
程式碼
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5001, MAXM = 2001;
int n, m, k, a[MAXN], log_2[MAXM], ans = int(1e9);
short st[MAXN][14][MAXM];
int Getmin(int i, int l, int r) {
return min(st[i][log_2[r - l + 1]][l], st[i][log_2[r - l + 1]][r - (1 << log_2[r - l + 1]) + 1]);
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
for(int i = 1; i <= n; ++i) {
cin >> a[i] >> a[i];
}
log_2[1] = 0;
for(int i = 2; i <= m; ++i) {
log_2[i] = log_2[i / 2] + 1;
}
for(int i = 1; i <= n; ++i) {
for(int j = 0; j < m; ++j) {
cin >> st[i][0][j];
}
for(int j = 1; j <= 13; ++j) {
for(int k = 0; k < m; ++k) {
if(k + (1 << j) - 1 < m) {
st[i][j][k] = min(st[i][j - 1][k], st[i][j - 1][k + (1 << (j - 1))]);
}
}
}
}
for(int i = 1; i <= n; ++i) {
if(a[i] > m - k) {
cout << -1;
return 0;
}
}
for(int i = 0; i < m; ++i) {
int res = 0;
bool ok = 1;
for(int j = 1; j <= n; ++j) {
int l = (i + k) % m, r = (i - a[j] + m) % m;
if(l <= r) {
res += Getmin(j, l, r);
}else {
res += min(Getmin(j, 0, r), Getmin(j, l, m - 1));
}
}
ans = min(ans, res);
}
cout << ans;
return 0;
}
C. 路徑難題
題目描述
你在一個城市中,可以看作一個 \(N\) 個點 \(M\) 條邊的圖,其中有一些邊連線這些點,你有兩種移動方式:
- 使用計程車移動。每次移動 \(l\) 個單位需要 \(\lceil \frac{l}{r}\rceil\) 的代價。
- 使用公交車移動。有 \(k\) 種線路,第 \(i\) 個線路可以讓你在 \(a_{i,1},a_{i,2},\dots,a_{i,t_i}\) 之間移動,每次移動需要 \(c_i\) 的代價。
有 \(Q\) 次查詢,每次查詢從 \(a_i\rightarrow b_i\) 的最小代價。
思路
對於公交車,我們可以建一箇中轉站 \(x_i\),並建邊 \(a_{i,j}\overset{c_i}\rightarrow x_i,x_i\overset{0}\rightarrow a_{i,j}\) 即可。
由於這裡 \(Q\le 10\),所以對於每次查詢暴力跑最短路。最短路中有兩個屬性:當前計程車走了多遠,總共花費了多少代價。
當總代價一樣時,很明顯計程車行走距離 \(\bmod r\) 更小的之後更優。
空間複雜度 \(O(N+M+K)\),時間複雜度 \(O((N+M+K)\log (N+K))\)。
程式碼
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int MAXN = 210001;
const ll INF = (ll)(1e18);
int r;
struct Node {
int u;
ll dis, cost;
ll Calc() const {
return cost + (dis + r - 1) / r;
}
bool operator<(const Node &b) {
return Calc() < b.Calc() || (Calc() == b.Calc() && dis % r < b.dis % r);
}
};
struct cmp {
bool operator()(const Node &a, const Node &b) const {
return a.Calc() > b.Calc() || (a.Calc() == b.Calc() && a.dis % r > b.dis % r);
}
};
struct INFO {
ll dis, cost;
ll Calc() const {
return cost + (dis + r - 1) / r;
}
bool operator<(const INFO &b) {
return Calc() < b.Calc() || (Calc() == b.Calc() && dis % r < b.dis % r);
}
}dist[MAXN];
int n, m, k, q;
bool vis[MAXN];
vector<pii> e[MAXN];
ll dij(int s, int t) {
priority_queue<Node, vector<Node>, cmp> pq;
for(int i = 1; i <= n + k; ++i) {
dist[i] = {INF, INF};
vis[i] = 0;
}
pq.push({s, 0, 0}), dist[s] = {0, 0};
for(; !pq.empty(); ) {
auto [u, dis, cost] = pq.top();
pq.pop();
if(u == t) {
return cost + (dis + r - 1) / r;
}
if(vis[u]) {
continue;
}
vis[u] = 1;
for(auto [v, w] : e[u]) {
ll nowd = (u <= n && v <= n ? dis + w : 0ll), nowc = cost + (u <= n && v <= n ? 0ll : w + (dis + r - 1) / r);
if(INFO{nowd, nowc} < dist[v]) {
dist[v] = INFO{nowd, nowc};
pq.push({v, nowd, nowc});
}
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m >> k >> r >> q;
for(int i = 1, u, v, w; i <= m; ++i) {
cin >> u >> v >> w;
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
for(int i = 1, t, c; i <= k; ++i) {
cin >> t >> c;
for(int j = 1, x; j <= t; ++j) {
cin >> x;
e[x].emplace_back(n + i, c);
e[n + i].emplace_back(x, 0);
}
}
for(int i = 1, u, v; i <= q; ++i) {
cin >> u >> v;
cout << dij(u, v) << "\n";
}
return 0;
}