[20052006-ptz] Decoding Martian Messages
每日一练做到的, 做不来.
Decoding Martian Messages
算法
动态规划, 字符串.
思路
首先可以看出这是一道动态规划的题目.
这道题要求输出最终的字符串而非答案, 我们可以考虑先计算出答案数组再反推出最终的字符串.
先来考虑动态规划. 我们令 \(f_{i, j}\) 表示枚举到答案的第 \(i\) 位, 当前位填的是给定单词集合 \(\mathbb{D}\) 中的第 \(j\) 个字符串的"最后一位"的最大概率. 注意, 这里的"最后一位"在 \(i < k\) 时实际上是第 \(j\) 个字符串的第 \(i\) 位而并非真正的最后一位.
那么有转移方程:
其中 \(p_{i, s}\) 表示在第 \(i\) 位填字符 \(s\) 的概率, 已经在输入中给出. 其中 \(\textrm{check}(j, k)\) 指的是单词集合中两字符串的关系是否如下图所示.
只有这样才能够合法地转移, 同时 \(\textrm{check}\) 可以 \(\mathcal{O}(d^2 k)\) 的复杂度内预处理出.
这样, 我们成功地处理出了 \(f\) 数组, 现在来思考如何推出答案.
假设 \(f_{n, pos}\) 为最终答案, 那么根据定义, 答案的最后一位即为第 \(pos\) 个字符串的最后一位.
再来倒序枚举每一位, 考虑什么时候第 \(n - 1\) 位合法? 枚举 \(\mathbb{D}\) 中每一个字符串, 首先 \(\textrm{check}\) 函数需要合法, 其次 \(f_{n - 1, k} \times p_{n, s} = f_{n, pos}\). 以此类推, 我们动态地维护一个 \(now\), 表示当前位是 \(\mathbb{D}\) 中第 \(now\) 个字符串的最后一位, 转移即可.
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
using namespace std;
constexpr int N = 2e2 + 10, M = 1e3 + 10;
int d, k, t, n, flag[N][N];
char s[N][30], ans[M];
long double p[M][30], f[M][N];
void init() {
cin >> d >> k >> t;
for (int i = 1; i <= d; ++i)
cin >> (s[i] + 1), f[0][i] = 1;
for (int i = 1; i <= d; ++i)
for (int j = 1; j <= d; ++j) {
int t = 1;
for (int l = 1; l ^ k; ++l)
if (s[i][l] != s[j][l + 1]) {
t = 0;
break;
}
flag[i][j] = t;
}
cin >> n;
for (int i = 1; i <= n; ++i)
for (int j = 0; j ^ t; ++j) cin >> p[i][j];
}
void calculate() {
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= d; ++j) {
int nw = s[j][min(k, i)] - 'a';
if (i <= k) {
f[i][j] = f[i - 1][j] * p[i][nw];
continue;
}
for (int l = 1; l <= d; ++l) if (flag[j][l])
f[i][j] = max(f[i][j], f[i - 1][l] * p[i][nw]);
}
long double mx = 0;
for (int i = 1; i <= d; ++i)
mx = max(mx, f[n][i]);
if (mx == 0) return cout << "---", void();
for (int i = 1; i <= d; ++i) if (f[n][i] == mx) {
ans[n] = s[i][k];
int nw = i;
for (int j = n - 1; j >= k; --j)
for (int l = 1; l <= d; ++l)
if (flag[nw][l] and f[j + 1][nw] == f[j][l] * p[j + 1][s[nw][k] - 'a']) {
ans[j] = s[l][k];
nw = l;
break;
}
for (int j = k - 1; j; --j)
ans[j] = s[nw][j];
break;
}
for (int i = 1; i <= n; ++i) cout << ans[i];
}
void solve() {
init();
calculate();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
while (T--) solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步