最近因为学课内课程,写博客有些耽搁了,罪过罪过,毕竟年级高了,专业课也不能单单划水。不只是为应付考试,同时也是为了基础打好。之后的话我也会尽量花时间在算法上的。话不多说,看题。
题意:
将一个长度为n的字符串s,分成k个字符串,不要求是子序列或子段,所有的字母来自字符串s就好。(也就是所有的字符串的字母合起来排列一下正好能形成字符串s)。
要求是要使k个字符串中字典序最大的字符串,字典序尽可能的小。
想法:
主要还是题目写太少了了,熟练的话可以快速ac。
题解:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
ll t,n,m,k;
ll a[100];
int vis[200];
string s;
int ju(int x,int y)
{
if(x%y){
return x/y+1;
}else return x/y;
}
void solve(){
cin>>n>>k;
cin>>s;
sort(s.begin(),s.end());
if(s[0]!=s[k-1]){
cout<<s[k-1]<<endl;
return;
}
cout<<s[0];
if(s[k]!=s[n-1]){
for(int i=k;i<n;i++){
cout<<s[i];
}
}
else{
m=ju(n-k,k);
for(int i=0;i<m;i++){
cout<<s[n-1];
}
}
cout<<endl;
}
int main()
{
cin>>t;
while(t--){
solve();
}
return 0;
}
思路:
一个字符串,分成k组,
先将字符串排序;
字典序最小的那k个字母代表每组的第一个字母;
如果排在第k个的字母与第一个字母不一样的话,就代表第k组的字典序现在是最大的,直接结束。第k组的字母只有一个。同时因为这第一个字母是最大的。所以保证了最大的那组字典序尽量的小。
如果前k个字母都一样呢?
那就看后面那n-k个字母。
在后面的n-k个字母中,
如果第k+1个字母和第n个字母不一样的话,
就直接将后面的这n-k个字母接在后面,这样保证了在每一位都是最小的。
如果后面的这些字母也都一样的话,就直接数一下。
如果(n-k)/k 能整除的话,直接输出这么多个s[n-1];
不然就输出(n-k)/k+1个s[n-1]
标程:
#include <bits/stdc++.h>
using namespace std;
void solve(){
int n,k;
cin>>n>>k;
string s;
cin>>s;
sort(s.begin(),s.end());
//if smallest k letters are not all the same, answer is kth smallest letter
if (s[0]!=s[k-1]){
cout<<s[k-1]<<endl;
return;
}
cout<<s[0];
//if remaining letters aren't the same, we append remaining letters to answer
if (s[k]!=s[n-1]){
for (int i=k;i<n;i++)
cout<<s[i];
}
else{
//remaining letters are the same, so we distribute evenly
for (int i=0;i<(n-k+k-1)/k;i++)
cout<<s[n-1];
}
cout<<endl;
}
int main(){
int t; cin>>t;
while (t--)
solve();
}
标程的区别在于没有多一步判断。
为什么(n-k+k-1)/k这样能减少一步判断呢?
因为c++里除法的逻辑是每次整除则加一,有余数就向下取整。
这里我们这步判断其实就是余数为1的时候就加一,之后到下次能整除是都是和这次余数为1时的商相同。
所以(n-k+k-1)这样就可以实现n-k余数为1的时候正好进1.因为整体(n-k+k-1)正好可以被整除。