CF1527 E2. Erase and Extend (Hard Version)

Problem - E2 - Codeforces

 

题意:

给出一个长为n的字符串,你可以进行2种操作

1、把串在后面再拼接一次

2、删去串的最后一个元素

要求用这两种操作得出字典序最小的长为m的串

 

首先答案肯定是由一个前缀拼接多次构成

假设当前的最优前缀是A前缀,长度为LA,现在正在考虑的是B前缀

1、如果s[B%LA]和s[A]一样,那么不用管继续往后走

2、如果s[B%LA]比s[A]小,那么B前缀比A前缀更优秀

3、如果s[B%LA]比s[A]大,那么A前缀比B前缀更优秀

先来看2和3的正确性

在1的条件下,他们都包含了s[0…A]拼接多次=s[0…B-1]

所以只需要比较s[B%LA]与s[A]即可

然后是1的正确性,它包含了s[0…A]拼接多次=s[0…B]

令B%LA=t,可以把前B的字符分为3段

s[0…t]一段记为X,s[t+1,LA-1]一段记为Y,s[LA…B]一段等同于s[0…t]

如果还是用A前缀,那么拼接结果是XYXYXYXY

如果改为用B前缀,那么拼接结果是XYXXYXXY

所以如果YX<XY,那么还是原先的A前缀

如果XY<YX,才会改用B前缀

但是如果XY<YX,XY的拼接就不会是最小的,因为X的拼接会给更小

 

#include<bits/stdc++.h>
 
using namespace std;
 
#define N 500003
 
char s[N];
 
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    int len=1;
    for(int i=1;i<n;++i)
        if(s[i]<s[i%len]) len=i+1;
        else if(s[i]>s[i%len]) break;
    int now=0;
    for(int i=1;i<=m;++i)
    {
        printf("%c",s[now]);
        ++now;
        if(now==len) now=0; 
    }
}

 

posted @ 2021-10-04 11:42  TRTTG  阅读(136)  评论(0编辑  收藏  举报