【C题】Codeforces Round #638 (Div. 2)

本文讨论了一道编程竞赛题目,要求将一个字符串分成k个字符串,所有字母来自原字符串,目标是最小化字典序最大的子串。解决方案包括先排序字符串,然后确定每个子串的第一个字母,通过比较找到最佳分割方式。文章提供了详细的思路和标程解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近因为学课内课程,写博客有些耽搁了,罪过罪过,毕竟年级高了,专业课也不能单单划水。不只是为应付考试,同时也是为了基础打好。之后的话我也会尽量花时间在算法上的。话不多说,看题。

在这里插入图片描述
题意:
将一个长度为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)正好可以被整除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值