您的位置:首页 > 产品设计 > UI/UE

AtCoder regular contest 081 E - Don't Be a Subsequence

2017-08-21 00:22 489 查看
原题链接:http://arc081.contest.atcoder.jp/tasks/arc081_c

题目大意:给出一个小写字母构成的字符串,求满足2个条件的字典序最小的字符串:

1.不是这个字符串的子序列;

2.长度最短;

先把整个给定的字符串S倒序处理一下,每次集齐26个字母就把set清空并把这一区间划归为同一组

(令区间范围为 [ Li , Ri ] )( 1<=i<=tot) 

则可以知道长度为tot的所有字符串都为S的子序列,而且存在长度为tot+1的字符串不是S的子序列,所以答案串的长度为tot+1

令串S从第 i 个字符开始的后缀为 suffix ( i )

令答案串为ans

令答案串到第 i 个字符开始的前缀第一次作为S的子序列出现的位置为 pos( i )

显然ans[ 1 ]是[ 1 , L1 )区间内没出现过的字符,否则,以这个字符为开头的长度为tot+1的字符串都是S的子序列

然后当前的问题就转化为了 获得长度为tot且不是 suffix( pos( 1 ) )的子序列的字典序最小的字符串,显然除了第一组,其他的分组仍然没有变,这样我们所求的ans[2]一定是[ pos(1) , L2)区间内没出现过的字符,否则,以这个字符ans[2]的长度为tot的字符串都是S的子序列,

如此递推处理,就会得到一个长度为tot的字符串,最后一个字符只要是[ pos(tot) ,len]区间内没有出现过的字符就是满足条件的。

显然每次在取答案串的字符的时候就可以贪心取最小的字符就可以保证是字典序最小的答案串。

代码:

#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <bits/stdc++.h>
#define mp make_pair
using namespace std;

constexpr int maxn = 2000010;
char s[maxn];

set <int> S;
int nextt[maxn][30];
int now[30];
int now_tot[maxn];

void doit(){
scanf("%s",s);
int len=strlen(s);
int tot=0;
for (int i=len;i>=1;i--)
{
S.insert( s[i-1]-'a' );
now_tot[i]=tot;
if (S.size()==26)
{
tot++;
S.clear();
}
}
if (tot==0)
{
for (int i=0;i<26;i++)
if (S.count (i )==0)
{
printf("%c",i+'a');
return ;
}
}
memset(now,0,sizeof(now));
for (int i=len;i>=1;i--)
{
for (int j=0;j<26;j++)
nextt[i][j]=now[j];
now[ s[i-1]-'a' ]=i;
}
int tmp=0;
for (int i=0;i<26;i++)
if (S.count (i )==0)
{
tmp=now[i];
break;
}
printf("%c",s[tmp-1]);
for (int i=1;i<tot;i++)
{
for (int j=0;j<26;j++)
if (now_tot [ nextt[ tmp ][ j ] ]==now_tot [ tmp ] -1 )
{
tmp=nextt[ tmp ][ j ];
printf("%c",s[tmp-1]);
break;
}
}
for (int i=0;i<26;i++)
if (nextt[ tmp ][ i ]==0)
{
printf("%c",i+'a');
break;
}
}

int main(){
doit();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: