【CF1348C】Phoenix and Distribution(构造、贪心)

发布时间 2023-08-25 21:01:55作者: Alric

题目大意:
将给定的\(n(1\le n\le10^{5})\)个字符分配为\(k\)个字符串(不能有空串),求此操作得到的字典序最大的字符串最小的情况。

我们先将给定的字符按照字典序从小到大排序,然后逐个分配给字符串。我们要让字典序最大的字符串尽可能小,所以将第\(i\)个字符安排在第\(i\)字符串的头部,这时第\(k\)个字符安排在第\(k\)个字符串头部,现在设该字符串为字典序最大的字符串。接着对于不同的情况我们进行分类讨论:

1.\(1\)个字符与第\(k\)个字符不相同。

在这种情况下,我们可以把剩下的\((n-k)\)个字符安排在前面的字符串中,例如:将所有\((n-k)\)个字符排在第\(i\)个字符串末尾。第\(i\)个字符串为与第\(k\)个字符串开头不同的字符串中最编号最大的字符串。经过此操作后,第\(k\)个字符串仍然为字典序最大的字符串。

这时第\(k\)个字符串只有一个字符,即\(s[k]\)(字符数组\(s\)已经过排序)。

2.\(1\)个字符到第\(k\)个字符全部相同,第\(k+1\)个字符到第\(n\)个字符全部相同。

这种情况下我们考虑在不影响字符串间的字典序的前提下,使第k个字符串尽可能短。

所以选择平均分配剩下的\(n-k\)个字符到各个字符串的末尾。这时第k个字符串末尾多出了\(\lceil \frac{n-k}{k} \rceil\)\(s[n]\)

3.\(1\)个字符到第\(k\)个字符全部相同,第\(k+1\)个字符和第\(n\)个字符不同。

为了使第\(k\)个字符串字典序尽可能小,先使其第\(2\)个字符字典序尽可能小,然后第\(3\)个字符……直到字符串的末尾。

因此我们选择将剩下的\((n-k)\)个字符按照字典序从小到大逐个插入第\(k\)个字符串的末尾。若不如此做,将其中的某些字符插入前面字符串的末尾,则会使第\(k\)个字符串最终的字典序变大。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
char s[100000+10];
int main(){
	int T;
	cin >> T;
	while(T--){;
		cin >> n >> k >> (s+1);
		sort(s+1,s+1+n);
		if(s[1]!=s[k]){
			cout << s[k];
		}else if(s[k+1]==s[n]){
			cout << s[k];
			for(ll i=1;i<=(n-k+k-1)/k;i++){
				cout << s[k+1];
			}
		}else{
			for(ll i=k;i<=n;i++){
				cout << s[i];
			}
		}
		cout << endl;
	}
	return 0;
}