@description@

给定一个长度为 N 且只包含小写字母的字符串 S ,你可以执行 k 次操作,每次操作你可以:

(1)将 S 翻转得到 T,将 S 与 T 拼接得到 U。

(2)从 U 中取出长度为 N 的子串 S',替换当前 S 进行下一轮迭代。

你需要求出 k 次操作后字典序最小的 S。

Constraints

1≤N≤5000, 1≤K≤10^9, |S|=N。保证 S 只包含小写字母。

Input

输入格式如下:

N K

S

Output

输出 K 次操作后字典序最小的字符串。

Sample Input 1

5 1

bacba

Sample Output 1

aabca

S=bacba, T=abcab, U=bacbaabcab, S′=aabca。

Sample Input 2

10 2

bbaabbbaab

Sample Output 2

aaaabbaabb

@solution@

是我太傻。。。

k 这么大,是否一定操作过后字符串就恒定不变呢?

那么我们不妨大胆猜测,一定操作过后,字符串变成只含有最小字母 mn 的字符串("aaa...a" 型)。

最少多少次呢?假如我们 S 有一个以 mn 结尾的长度为 p 的连续段,则 U 的中间就有 2*p 的连续段。

假如我们选择以这 2*p 个 mn 为结尾的 S',我们又可以得到 4*p 个 mn 结尾的 S'' 等。即:mn 的数量可以呈指数级增长。

同时,只有末尾的连续段才会有这个性质,不在末尾的甚至不会与另一个字符串 T 产生关系。

当 k > log|S| 时,我们可以直接输出答案了。剩下的只需要讨论 k <= log|S| 的时候

根据字典序的定义,我们想让前面的字符尽可能地字典序小。

而最后一次我们可以让 mn 直接放在字符串的开头,这样 mn 越多显然越优秀。

于是我们的贪心策略就是:枚举第一次操作选择的字符串,然后按照上面所说,将末尾的连续段翻倍再翻倍。

最后一次再把连续段作为开头截取下来,得到最终的字符串。

你以为要暴力模拟过程?NONONO!

我们在最后一次之前,末尾连续段之前的那些 “冗余” 部分的相对顺序是不会变的,保持着在原串中的顺序。

而最后一次只是把那些 “冗余” 部分翻转一下,所以可以直接得到最终字符串。

因为更新答案是暴力比较的,所以时间复杂度是 O(n^2) 的。

@accepted code@

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. const int MAXN = 5000;
  5. char str[2*MAXN + 5], mn;
  6. char ans[MAXN + 5];
  7. int N, K;
  8. bool check(char *S) {
  9. for(int i=1;i<=N;i++)
  10. if( ans[i] != S[i] )
  11. return ans[i] > S[i];
  12. return false;
  13. }
  14. void update(char *S) {
  15. for(int i=1;i<=N;i++)
  16. ans[i] = S[i];
  17. }
  18. int pw[35];
  19. char S[MAXN + 5];
  20. int main() {
  21. pw[0] = 0, pw[1] = 2;
  22. for(int i=2;i<=30;i++) pw[i] = 2*pw[i-1];
  23. scanf("%d%d%s", &N, &K, str + 1);
  24. mn = 'z';
  25. for(int i=1;i<=N;i++)
  26. mn = min(mn, str[i]), ans[i] = 'z';
  27. if( K >= 30 ) {
  28. for(int i=1;i<=N;i++)
  29. putchar(mn);
  30. }
  31. else {
  32. for(int i=1;i<=N;i++)
  33. str[2*N - i + 1] = str[i];
  34. int cnt = 0;
  35. for(int i=1;i<N;i++)
  36. cnt = (str[i] == str[i-1]) ? cnt + 1 : 1;
  37. for(int i=N;i<=2*N;i++) {
  38. cnt = (str[i] == str[i-1]) ? cnt + 1 : 1;
  39. if( pw[K - 1] <= N/cnt ) {
  40. for(int j=1;j<=pw[K-1]*cnt;j++)
  41. S[j] = str[i];
  42. int k = i - cnt;
  43. if( K == 1 ) k = i;
  44. for(int j=pw[K-1]*cnt+1;j<=N;j++)
  45. S[j] = str[k--];
  46. }
  47. else {
  48. for(int j=1;j<=N;j++)
  49. S[j] = str[i];
  50. }
  51. if( check(S) ) update(S);
  52. }
  53. puts(ans + 1);
  54. }
  55. }

@details@

可能是自己还不大擅长贪心。。。

贪心太难了。。。

@AGC037 - E@ Reversing and Concatenating的更多相关文章

  1. [Atcoder AGC037E]Reversing and Concatenating

    题目大意:有一个长度为$n$的字符串$S$,有$k$次操作,每次操作为把$S$变为$SS^R$(即翻转后再接在一起),然后从中选取一段长度为$n$的字串.问$k$次操作后,字典序最小的一种是什么.$n ...

  2. AtCoder Grand Contest 037

    Preface 这篇咕了可能快一个月了吧,正好今天晚上不想做题就来补博客 现在还不去复习初赛我感觉我还是挺刚的(微笑) A - Dividing a String 考虑最好情况把每个字符串当作一个来看 ...

  3. AtCoder Grand Contest 037 简要题解

    从这里开始 题目目录 Problem A Dividing a String 猜想每段长度不超过2.然后dp即可. 考虑最后一个长度大于等于3的一段,如果划成$1 + 2$会和后面相同,那么划成$2 ...

  4. Assembler : The Basics In Reversing

    Assembler : The Basics In Reversing Indeed: the basics!! This is all far from complete but covers ab ...

  5. 02-线性结构2 Reversing Linked List

    由于最近学的是线性结构,且因数组需开辟的空间太大.因此这里用的是纯链表实现的这个链表翻转. Given a constant K and a singly linked list L, you are ...

  6. 单链表反转的递归实现(Reversing a Linked List in Java, recursively)

    转自Reversing a Linked List in Java, recursively There's code in one reply that spells it out, but you ...

  7. PAT1074 Reversing Linked List (25)详细题解

    02-1. Reversing Linked List (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue ...

  8. [Reversing.kr] Easy Crack Writeup

    题目:http://reversing.kr/ Easy Crack IDA打开.分析可知Sub_401080是关键函数.F5后. 当满足 则跳转成功.拼接后得到flag flag: Ea5yR3ve ...

  9. PAT 1074 Reversing Linked List[链表][一般]

    1074 Reversing Linked List (25)(25 分) Given a constant K and a singly linked list L, you are suppose ...

随机推荐

  1. 学习Web前端开发时有哪些技术点

    现在学前端的人是越来越多,学习质量也是参差不齐.过来人的身份告诉你,如果你还没有下定决心花时间去学习Web前端,那也可以先找些视频学习下,Web前端开发有哪些常见技术点!接下来,就看看Web前端开发有 ...

  2. DEV GridControl 控件属性大全

    Devpress.XtraGrid.GridControl.GridView 属性 说明 Options OptionsBehavior 视图的行为选项 AllowIncrementalSearch ...

  3. C#中int short Int16 Int32 Int64区别

    Java中没有Int32,Int64,,java中只有int,short,long Java中int就代表Int32 ,short就代表Int16,long就代表Int64 首先,几个基本的关键字: ...

  4. CSS Reset(CSS重置)

    CSS Reset是指重设浏览器的样式.在各种浏览器中,都会对CSS的选择器默认一些数值,譬如当h1没有被设置数值时,显示一定大小. 但并不是所有的浏览器都使用一样的数值,所以有了CSS Reset, ...

  5. free内存监控

    语 法: free [-bkmotV][-s <间隔秒数>] 补充说明:free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共享内存区段,以及系统核心使用的缓冲区等. 参 ...

  6. winform应用程序异常处理

    对于winform应用程序补抓异常信息,我们经常用到得try catch. 如果代码中在某个地方执行异常,但是没有加try catch,这个时候就需要做一些全局异常捕捉. 怎么做到全局异常捕捉.win ...

  7. SQL Server删除用户失败的解决方法

    在删除SQL Server用户时,有时会报错:Microsoft SQL Server错误: 15138删除对于用户失败,数据库主体在该数据库中拥有架构,无法删除.删除 对于 用户“*****”失败. ...

  8. 扩展 Microsoft.Owin.Security

    微软在 OWIN 框架中对 OAuth 认证的支持非常好, 使用现有的 OWIN 中间件可以做到: 使用 Microsoft.Owin.Security.OAuth 搭建自己的 OAuth2 服务端, ...

  9. Linux SSH远程链接 短时间内断开

    Linux SSH远程链接 短时间内断开 操作系统:RedHat 7.5 问题描述: 在进行SSH链接后,时不时的就断开了 解决方案: 修改 /etc/ssh/sshd_config 文件,找到 Cl ...

  10. 使用 javascript 替换 jQuery

    使用 javascript 替换 jQuery jQuery 曾风靡一个时代,大大降低了前端开发的门槛,丰富的插件也是前端开发者得心应手的武器库,但是,这个时代终于要落幕了.随着 JS 标准和浏览器的 ...