FJOIP 2021
QOJ 6147 赛车竞技
最短路的边数一定不超过 \(n - 1\),所以换乘的次数一定不会超过 \(n - 1\)。
于是设 \(f_{i, x, y}\) 表示换乘了 \(i\) 次,\(x\to y\) 的最短路。
转移就枚举最后一次换乘即可,\(f_{i - 1, x, z} + f_{0, z, y}\to f_{i, x, y}\)。
对于 \(f_{0, x, y}\) 的预处理可以直接对 \(m\) 个图跑 floyd 后取 \(\min\)。
时间复杂度 \(\mathcal{O}((n + m)n^3 + q)\)。
代码
#include<bits/stdc++.h>
constexpr int maxn = 80 + 2;
int d[maxn][maxn], dis[maxn][maxn][maxn];
int main() {int n, m, q;scanf("%d%d%d", &n, &m, &q);memset(dis, 0x3f, sizeof(dis));for (; m--; ) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {scanf("%d", &d[i][j]);}}for (int k = 1; k <= n; k++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {d[i][j] = std::min(d[i][j], d[i][k] + d[k][j]);}}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {dis[i][j][1] = std::min(dis[i][j][1], d[i][j]);}}}for (int d = 2; d <= n; d++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {for (int k = 1; k <= n; k++) {dis[i][j][d] = std::min(dis[i][j][d], dis[i][k][d - 1] + dis[k][j][1]);}}}}for (int s, t, k; q--; ) {scanf("%d%d%d", &s, &t, &k);printf("%d\n", dis[s][t][std::min(k + 1, n)]);}return 0;
}
QOJ 6148 宝石项圈
考虑这个金珠不能相邻,就说明了金珠的前后一定得是个银珠。
于是考虑捆绑,把 金珠-银珠 捆绑到一起和单独的银珠考虑,放的是两个物品就能保证不会出现相邻的金珠。
接下来考虑断环成链设计 dp。
令 \(f_i, {0 / 1}\) 表示放了 \(i\) 个珠子,有偶数 / 奇数个金珠的方案数。
转移考虑 \(i\) 这里放的是什么珠子,有 \(f_{i, j} = f_{i - 1, j} + f_{i - 2, 1 - j}\)。
对于统计答案,一个贡献肯定就是 \(f_{n, 1}\)。
但是断环成链的过程中可能破坏了 \(n\) 和 \(1\) 的 金珠-银珠 的捆绑,那么这个时候就可以直接删去这两个固定下来珠子,剩下的 \(n - 2\) 个任意组合即可,所以还有个 \(f_{n - 2, 0}\) 的贡献。
时间复杂度 \(\mathcal{O}(Tn)\),可以用矩阵优化到 \(\mathcal{O}(Tw^3\log n)\),其中 \(w = 4\)。
代码
#include<bits/stdc++.h>
using ll = long long;
constexpr int maxn = 1.2e5 + 10;
ll f[maxn][2];
int main() {int n; ll mod;while (~ scanf("%d%lld", &n, &mod)) {f[0][0] = 1ll;for (int i = 1; i <= n; i++) {for (int v : {0, 1}) {f[i][v] = (f[i - 1][v] + (i > 1 ? f[i - 2][v ^ 1] : 0ll)) % mod;}}printf("%lld\n", (f[n][1] + (n > 1 ? f[n - 2][0] : 0ll)) % mod);}return 0;
}
剩下的吃完饭来写。