【题解】ABC225F - String Cards

题意

给定 \(n\) 个仅由小写英文字母组成的字符串,从中选出 \(k\) 个,以任意顺序排列,使得得到的字符串字典序最小。
输出字典序最小的字符串。

做法

先将所有字符串按照如下方式排序:

bool cmp(string A, string B){
  return A+B<B+A;
}

然后DP。
设 \(dp[i][j]\) 表示从后 \(i\) 个字符串中选择 \(j\) 个能得到的字典序最小的字符串,转移如下:
\(dp[i][j]=min(dp[i+1][j],str[i]+dp[i+1][j-1])\)
答案即为 \(dp[1][k]\)。
妙就秒在把贪心决策提前处理了。
而且这个DP为什么是从后往前而不是从前往后,因为我们的目的是保证字典序最小,字典序更注重前面部分的串而不是后面,把后面都处理好了那么前面的大小可以决定一切。

代码

string st[maxn];
string dp[maxn][maxn];
bool cmp(string A, string B){
	return A+B < B+A;
}
int main(){
	n=rd(); k=rd();
	for(int i(1);i<=n;++i){
		cin >> st[i];
		len += st[i].size();
		ln[i] = st[i].size();
		for(int j(0);j<ln[i];++j){
			hs[i]*=26; hs[i]+=st[i][j];
		}
	}
	sort(st+1,st+1+n,cmp);
	for(int i(1);i<=n+1;++i)
		dp[i][n-i+2]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
	for(int i(n);i>=1;--i){
		for(int j(1);j<=n-i+1;++j){
			dp[i][j]=min(dp[i+1][j],st[i]+dp[i+1][j-1]);
//			printf("dp[%d][%d]=",i,j);cout<<dp[i][j]<<"\n";
		}
	}
	cout << dp[1][k] << "\n";
}
上一篇:CF254A Cards with Numbers 题解


下一篇:使用SuperSocket开发联网斗地主(一):发牌