题目链接:https://codeforces.com/contest/1537/problem/E2
题目大意:
有一个长度为n的初始字符串s,由小写字母组成,可以进行如下两种操作:
1,若s的字符数大于1,可删除s末尾的字符
2,在s的末尾加上自身,
可以进行无限次上述操作,我们需要得到一个长度为k的字符串,需要让该字符串的字典序最小。
题解:
个人的解法:贪心
1,若首字符为a,那么目标字符串一定为aaaaaa,我们可以首先构造出仅由构造的一个方案,寻找比它更优的方案
2,继续推导,若,则
及其后面的字符一定会被删除
3,剩下的字符,我们首先可以确定,第一个字符后,连续的比它小的字符一定必选。例如:,那么
这个前缀是必选的。继续推导,若前缀1到i-1的字符必选,且
,则s[i]必选。
4,我们如何判断接下来的字符串如何选,我们设,且前i个字符必选。设
表示s[i]到s[j]连续的子串,那么:
若,则s[i]及其之后的字符必定不选
若,此时s[i]到s[i+1]的字符串必选,选择以后并不会降低结果的字典序。
若,则s[i]是必选的
最后,若s[i]后缀的长度不足,则只有在s[i]的后缀小于前面已选的字符串的情况下,s[i]才必选
注意代码实现细节,复杂度
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int nn =5100;
const int inff = 0x3fffffff;
const double eps = 1e-8;
typedef long long LL;
const double pi = acos(-1.0);
const LL mod = 1000000007;
int n,k;
string s;
int main()
{
cin>>n>>k;
string s;
cin>>s;
string pre;
pre="";
pre+=s[0];
for(int i=1;i<n;i++)
{
if(s[i]>s[0])
break;
if(s[i]<s[0])
pre+=s[i];
else {
int lp=pre.size();
bool ok=true;
int tj=-1;
for(int j=0;j<lp;j++)
{
string tem;
if(i+j<n)
tem=s[i+j];
else
tem=s[(i+j)%n];
if(tem[0]<s[j])
{
tj=i+j;
break;
} else if(tem[0]>s[j]) {
ok=false;
break;
}
}
if(!ok)
{
break;
} else {
for(int j=0;j<lp&&(i+j)<n;j++)
{
if(tj!=-1&&i+j>tj&&s[i+j]>=s[0])
{
break;
}
pre+=s[i+j];
//cout<<i<<" "<<j<<" "<<pre<<endl;
}
i=pre.size()-1;
}
}
}
while(pre.size()<k)
{
pre=pre+pre;
}
for(int i=0;i<k;i++)
cout<<pre[i];
cout<<endl;
return 0;
}
官方解法:
若前缀为当前找到的最优解,我们如何判断前缀
是否更优呢?
若小于由目前的最优解构成的目标串位置j的字符,则前缀
更优
反之则大于,则j及其后面的字符一定不会产生更优的解
接下来是等于的情况,如何处理?
具体来说,就是当时,如何处理
我们设,则目标串有两种构造形式
或
我们需要判断和
谁更优
我们可以预处理出Z_Function,然后O(1)判断
Z_Function的定义:Z[i]表示从i开始的子串和原串最大匹配长度。可以O(n)的复杂度求出所有Z[i]。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int nn =210000;
const int inff = 0x3fffffff;
const double eps = 1e-8;
typedef long long LL;
const double pi = acos(-1.0);
const LL mod = 1000000007;
vector<int> Z_Function(string &s)
{
int ls=s.size();
vector<int>z(ls);
z[0]=ls;
int l=0,r=1;
for(int i=1;i<ls;i++)
{
if(i==r)
{
while(r<ls&&s[r-i]==s[r])
{
r++;
}
z[i]=r-i;
l=i;
if(i==r)
r++;
} else {
if(i+z[i-l]>=r)
{
z[i]=r-i;
while(r<ls&&s[z[i]]==s[r])
{
z[i]++;
r++;
}
l=i;
} else {
z[i]=z[i-l];
}
}
}
return z;
}
int main()
{
int n,k;
string s;
cin>>n>>k;
cin>>s;
vector<int> z=Z_Function(s);
int cur=0;
for(int i=1;i<n;i++)
{
if(s[i]<s[i%(cur+1)])
{
cur=i;
continue;
} else if(s[i]>s[i%(cur+1)]) {
break;
}
if(z[cur+1]<i-cur)
{
if(s[cur+z[cur+1]+1]<s[z[cur+1]])
continue;
else
cur=i;
continue;
}
int id=i-cur;
if(z[id]<2*cur-i+1)
{
if(s[id+z[id]]>s[z[id]])
{
cur=i;
break;
}
continue;
}
id=cur+1;
if(z[id]>=i-cur)
{
cur=i;
} else {
if(s[z[id]]<s[id+z[id]])
{
cur=i;
break;
}
}
}
string pre;
for(int i=0;i<=cur;i++)
pre+=s[i];
while(pre.size()<k)
{
pre=pre+pre;
}
for(int i=0;i<k;i++)
cout<<pre[i];
cout<<endl;
return 0;
}