Codeforces Round #726 (Div. 2) E1,E2

E1
题目大意:
给定一个长度为N(1<=N<=5000)的字符串S,以及一个数K(1<=K<=5000)
可以对S做以下2种操作:
1.去掉S的最后一个字符
2.把S变成S+=S
这2种操作可以进行无数次,要求把他变成长度为K的字符串,并且要求这个字符串是所有满足条件中的按字典序排序后,最小的
输出这个字符串

思路:对S的操作只有去掉最后一个,然后自加,所以最后变为K长度的字符串是可以暴力求出来的,首先是不去字符,自加,然后就是去一个,二个,三个 等等,然后进行自加。所以最后不同的结果只有N个,自加最多是只有一个字符的自加,要加K次,所以时间复杂度是O(NK)的,数据范围是1到5000,所以是可以过的。

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
int n,m;
int main()
{
    cin>>n>>m;
    string s;
    cin>>s;
    string t;
    vector<string> res;
    for(int i=0;i<s.size();i++)
    {
        t+=s[i];
        string dis;
        while(dis.size()<m) dis+=t;
        res.push_back(dis.substr(0,m));
    }
    sort(res.begin(),res.end());
    cout<<res[0]<<endl;
    return 0;
}

E2
E2和E1的唯一区别就是数据范围的变化
n, k (1≤n,k≤5*10^5)
所以就不能用上面的方法了
通过上面的暴力,可知所有情况的字符串,他的第一个字符必定是初始S的第一个字符

那么看第二个
第二个字符的情况只有第一个字符或者第二个字符
所以就判断
当s[1]>s[0]的时候就代表第二个为s[1]的字符串都可以排除了,因为他们一定比全是s[0]的字符串大,所以之后的都不用取了

当 s[1]<s[0]的时候,那么第二个为s[0]的就都排除了

当s[1]==s[0],就要看s[1]后面的是不是比s[0]后面的小了,小的话就取,不小的话,就不取

到第三个的时候,因为已经确定第二个位置放那个最小了,所以考虑第三个取不取,取决于加上他的自加是不是小于前2个自加到K长度的字符串,前2个自加后的,第3个位置是第一个字符,所以就判断s[2]和s[0]

当s[2]<s[0],的时候就取s[2]
当s[2]>s[0] ,那么之后的都不用取了, 肯定都比他小
s[2]==s[0],就需要判断了
到第4个的时候,就按照第三个的判断方式

所以总结起来方法就是:
找到一个自加后字典序最小的前缀,然后它进行自加

i:0~N
1.s[i]>s[0] ,就不用取了,自加最小的前缀就是0~i-1
2.s[i]<s[0],就取
3.s[i]==s[0]
就判断0后面的是不是比s[i]后面的小,是的就不取
不是就取

这个判断的话
就一直往后比
i从1开始,j从相等的小标i+1开始
s[i]>s[j]那么就取j
s[i]<s[j]就不取
s[i]==s[j]就继续走

时间复杂度O(N)

#include<iostream>
#include<string>
using namespace std;
int n,m;
string s;
int check(int x)
{
    for(int i=1,j=x+1;j<s.size();j++,i++)
    {
        if(s[i]>s[j]) return j;
        else if(s[i]<s[j]) return 0;
    }
    return 0;
}
int main()
{
    cin>>n>>m>>s;
    int res=1;
    for(int i=1;i<n;i++)
    {
        if(s[i]<s[0]) res=i+1;
        else if(s[i]>s[0]) break;
        else if(s[i]==s[0])
        {
            int j=check(i);
            if(j) res=j+1,i=j;
            else break;
        }
    }
    for(int i=0;i<m;i++)
    cout<<s[i%res];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值