【思维】C. Phoenix and Distribution

C. Phoenix and Distribution

题意:给定长度为n的字符串s,将s任意拆分成k个部分,求k个部分中字典序最大的最小字典序

思路:

因为是任意拆分,所以将s中的字母从小到大排序,那么字典序最小的字母为s[1],记它的个数为p

实际上要求的还是最小字典序,那么在构造这k个部分的过程中,应始终选用可选的最小字母

有三种情况:

1.\(p<k\),则\(k\)个部分中必有\(p\)个以s[1]开头,而第\(p+1\)个则以更大的字母开头,故第\(k\)个部分应以s[k]这个字母为开头,那么它一定是字典序最大的那个。由于要求最小字典序,则不应在其后继续接字母,剩余字母都将安排到\(p\)个部分中。所以答案应该为s[k]

2.\(k≤p<n\),则\(k\)个部分都以s[1]为开头,答案应在后直接接剩下所有的串,就直接能保证满足题意

3.\(p=n\),则k个部分平均分配所有字母才能保证答案是最小的字典序,答案应该是\(n/k\)个s[1]

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 3e5 + 10;
typedef long long LL;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a * b / gcd(a, b);}
char s1[100000 + 10];
int main()
{
	int t; cin >> t; while (t--){
		int n, k;
		cin >> n >> k;
		cin >> s1+1;
		sort(s1+1, s1 + n+1);//找出字典序前k小的字母
		if (s1[1] != s1[k]) cout << s1[k] << endl;
		//如果与s1[1]相同的字母小于k个,那么符合要求的答案必为s1[k]这个字母
		else if (s1[n] != s1[k + 1]) cout << s1[1] << s1 + k + 1 << endl;
		//如果与s1[1]相同的字母大于等于k个,但不是全部都相同
		//那么答案以s1[1]开头,后面接从k+1个字母开始的串
		else {
			//全部相同,平均分配
			cout << s1[1];
			for (int i = 1; i <= (n - 1)/ k; i++) cout << s1[k + 1];
			cout << endl;
		}
	}
	return 0;
}
posted @ 2020-05-14 20:22  StreamAzure  阅读(146)  评论(0编辑  收藏  举报