题解:P3881 [JLOI2008] CODES
zhangzhixing99 · · 题解
前情提要
暴力 DP 过了。
荣获最优解榜三。——
题意简述
给定
- 设这个序列为
p_1, p_2, \cdots, p_k ,则\forall \ i \isin [1, k], p_i \isin [1, n] ;s_{p_1} + s_{p_2} + \cdots + s_{p_k} = T ,其中a + b 表示字符串a 拼接b 。
求最短的
保证题目有解。
前置知识
- 动态规划。
-
- 实现上需要一些
\operatorname{set} 的技巧。正题开始
考虑从零开始拼接两个字符串,并关注当前两个串的差异,如:
- 样例中,其中一个串现在拼接到了
\texttt{00110} (s_2 + s_5 ),另一个串拼接到了\texttt{001100} (s_4 ),则它们的差异为\texttt{0} 。如果第一个串拼接为\texttt{001100110} ,而第二个串不变,则此时差异变为\texttt{110} 。
根据当前的长串的长度和差异进行
设
转移时,考虑在较短串上拼接新串
-
-
-
## 实现方法 注意到转移时,$i$ 增加或 $d$ 变短,所以先枚举 $i$,在从长到短枚举 $d$。
可以使用
时间复杂度
- 设
\max(s_i) = L, \max(i) = i_{max} 。 - 时间复杂度为
O(i_{max} \cdot n^2 \cdot L^2 \cdot \log_2 (n \cdot L)) ,实际上很难跑满。 - 所以时间复杂度取决于实现上
i_{max} 取到多少。实测i_{max} 取到400 即可。空间复杂度
- 取决于实现方法。
代码
#include <bits/stdc++.h> using namespace std;
define EOL '\n'
define int long long
define double long double
define sqrt sqrtl
struct Cmp { bool operator () (const string &s1, const string &s2) const { return s1.size() >= s2.size(); } };
string s[30]; map<string, string> f[410];
int read() { int ret = 0, neg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') { neg = -neg; } ch = getchar(); } while (isdigit(ch)) { ret = ret 10 + ch - '0'; ch = getchar(); } return ret neg; }
string reads() { string s = ""; char c = getchar(); while (!isdigit(c)) { c = getchar(); } while (isdigit(c)) { s += c; c = getchar(); } return s; }
void writes(string s) { for (char c: s) { putchar(c); } }
bool cmp(string s1, string s2) { if (s1.size() != s2.size()) { return s1.size() < s2.size(); } return s1 <= s2; }
signed main() { int n = read(); for (int i = 1; i <= n; ++i) { s[i] = reads(); } sort(s + 1, s + n + 1, cmp); for (int i = 1; i < n; ++i) { for (int j = i + 1; j <= n; ++j) { if (s[j].substr(0, s[i].size()) == s[i]) { int sz = s[j].size(); string t = s[j].substr(s[i].size()); if (!f[sz].count(t)) { f[sz][t] = s[j]; } else { f[sz][t] = min(f[sz][t], s[j]); } } } } for (int i = 1; i <= 400; ++i) { set<string, Cmp> se; for (pair<string, string> kv: f[i]) { se.insert(kv.first); } while (!se.empty()) { string d = *se.begin(), t = f[i][d]; se.erase(se.begin()); for (int j = 1; j <= n; ++j) { if (s[j].size() <= d.size()) { if (d.substr(0, s[j].size()) == s[j]) { string nd = d.substr(s[j].size()); if (!f[i].count(nd)) { f[i][nd] = t; } else { f[i][nd] = min(f[i][nd], t); } se.insert(nd); } } else { if (s[j].substr(0, d.size()) == d) { string nd = s[j].substr(d.size()); int sz = i + nd.size(); if (!f[sz].count(nd)) { f[sz][nd] = t + nd; } else { f[sz][nd] = min(f[sz][nd], t + nd); } } } } } if (f[i].count("")) { writes(to_string(i) + EOL + f[i][""] + EOL); return 0; } } return 3; }