Loading

【题解】ABC225 F - String Cards

思维不严谨被毒打了。(每日一个挂分小技巧

一个比较经典的 trick,重载小于号 \(a<b\)\(a+b < b+a\),最后答案序列一定是满足 \(S_{p_i} \le S_{P_{i + 1}}\)

然后我们直接 DP 即可,设 \(f_{i,j}\) 表示最后一个串是 \(S_i\),用了 \(j\) 个串的最小字典序,时间复杂度 \(\mathcal{O}(N^3|S|)\)

交了之后发现 WA 了三个点一直过不去。赛后才发现这个方法有一个致命的 bug。

由于我们的状态是答案串的前 \(j\) 个串拼接的最小字典序,但是字典序最小时,存在一个方案是另一个方案的前缀的情况,而对于这种情况,算法只能目光短浅的考虑长度较短的情况。例如以下这个 Hack 数据

4 3
bba
bbaba
b
b

所以我们应该倒着 DP,状态 \(f_{i,j}\) 表示当前第一个串是 \(S_i\) ,答案串最后 \(j\) 个串的最小字典序。这样我们 DP 时,对于一个方案是另一个方案前缀的情况,一定选择最短的,因为后面不会再接新的串,方案一定最优。

#define N 55
int n, k;
string a[N];
string f[N][N];
bool cmp(string x, string y){return x + y < y + x || (x + y == y + x && x.length() < y.length());}
int main() {
	//int T = read();while(T--)solve();
	n = read(), k = read();
	rp(i, n)cin >> a[i];
	sort(a + 1, a + n + 1, cmp);
	rep(i, 1, n + 1)rep(j, 0, n)f[i][j] = "~";
	f[n + 1][0] = "";
	pre(i, n, 1){
		rep(j, i + 1, n + 1)rep(p, 0, n + i - j){
			f[i][p + 1] = min(f[i][p + 1], a[i] + f[j][p]);
		}
	}
	rep(i, 1, n)cout << "ss " << a[i] << endl;
	string ans = "~";
	rep(i, 1, n - k + 1)ans = min(ans, f[i][k]);
	cout << ans << endl;
	return 0;
}
posted @ 2021-10-30 22:11  7KByte  阅读(157)  评论(0编辑  收藏  举报