1 条题解
-
0
自动搬运
来自洛谷,原作者为

cff_0102
& aqua_qaq | 团子群 185800038 | 如果我死了说明我 AFO 了搬运于
2025-08-24 23:07:22,当前版本为作者最后更新于2024-12-10 15:04:36,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
给定一个字符串 ,假设它的最大字符 在 中出现了 次,那么 一定以 个 开头。
给定两个字符串 ,假设它们的最大字符都是 ,且 在 中分别出现了 次。若 ,那么 在字典序上一定大于 ,因为它们开头的 的个数不一样。
因此,最终的划分方案中,一定要让每个子串中 出现的个数的最大值尽可能小。根据抽屉原理(鸽巢原理),这个数是 。
把那些出现个数更大的分段放到前面。除了最后一段外,让划分的边界刚好在每一段最后一个 的右边,这样前 段的 值都正好是 个 ,后面不会再有多余的字符,就做到了字典序尽量小。
如果 ,那么正确答案就是 个 ,因为最后一段的 的数量小于前面的 的数量,它的 值不可能成为最终的权值。
否则,最后一段的 的个数与前面相同,那么就还需要在最后一个 的后面加上从整个字符串的最后一个 的后缀最大字典序子序列。这个只需要提前预处理一下,记录下每个位置的后缀最大字符出现的位置即可。
#include<bits/stdc++.h> using namespace std; char s[240520]; int a[240520]; int main(){ ios::sync_with_stdio(0);cin.tie(0); int n,k;cin>>n>>k; vector<int>v; char mx=' '; cin>>s+1; for(int i=1;i<=n;i++)mx=max(mx,s[i]); for(int i=1;i<=n;i++)if(s[i]==mx)v.emplace_back(i); int pos=n;a[n]=n+1; for(int i=n-1;i>=1;i--){ a[i]=pos; if(s[i]>=s[pos])pos=i; } if(v.size()%k){ cout<<string(v.size()/k+1,mx); }else{ cout<<string(v.size()/k,mx); for(int i=a[v.back()];i<=n;i=a[i])cout<<s[i]; } return 0; }另注:上面代码中的
cin>>s+1从 C++20 开始就不能用了,会 CE。
- 1
信息
- ID
- 11070
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者