1. 程式人生 > 其它 >AT???? [ABC255D] String Cards 題解

AT???? [ABC255D] String Cards 題解

ATcoder

Description.

\(n\) 個字串,選出 \(K\) 個按任意順序連線。
求字典序最小的方案。

\(1\le k\le n\le 50\)

Solution.

首先,當 \(K=n\) 的情況是一個經典原題。
可以直接 sort(s.begin(),s.end(),[](string a,string b){return a+b<b+a;}); 就做完了。
這個滿足偏序也很好證明,可以直接算雜湊值。
這樣就有 \(a\times 26^{|B|}+b\le b\times26^{|A|}+a\),有 \(\frac{a}{26^{|A|}-1}\le \frac{b}{26^{|B|}-1}\)


同時,排完序後,選出來 \(K\) 個肯定會按原序列順序排序,證明顯然。

然後,\(K\ne n\) 的時候考慮 dp。
dp 要求的是全域性最優決策的部分肯定是區域性最優決策。
從前往右肯定有問題,因為 aaa 區域性最優決策是 a,但是後面連一個 b 就要選 aab
考慮從後往前,往前接一個相同的字串,後面肯定字典序越小越好。
所有從後往前 dp 就行了。

Coding.

點選檢視程式碼
//Coded by leapfrog on 2021.10.29 {{{
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
string s[55],dp[55][55];int n,K;
int main()
{
	read(n,K);for(int i=1;i<=n;i++) cin>>s[i];
	sort(s+1,s+n+1,[](string a,string b){return a+b<b+a;});
	for(int i=n;i>=1;i--)
	{
		dp[i][n-i+1]=s[i]+dp[i+1][n-i];
		for(int j=1;j<=n-i;j++) dp[i][j]=min(dp[i+1][j],s[i]+dp[i+1][j-1]);
	}return cout<<dp[1][K]<<endl,0;
}