时限:1000ms 空间限制:131072K
题目链接https://nanti.jisuanke.com/t/39614
VIPKID 是在线少儿英语教育平台,网络稳定是在线教育课程质量的红线,VIPKID 为此推出了全球最稳定的教育网络系统 —— “星云系统”。星云系统目前建立了覆盖全球 35 个国家的 5 条核心跨海专线,在 16 个国家的 55个城市建立了中心传输节点,具备一分钟内自由切换路由的能力,确保了全球跨洋课堂的高清音、视频通信,为流畅的课堂体验打下坚实基础。
全世界的中心传输节点和各地的网络节点组成的这个“星云系统”,何其复杂。我们现在只考虑一条支线上的网络节点,每一个网络节点比作一个字符的话,这条支线就是一个字符串。
现在给定你一个字符串 s 以及一个整数 k,请求出 s 的字典序最小的长度为 k 的子序列。
输入格式
第一行一个由小写英文字母构成的字符串 s,第二行一个正整数 k。
输出格式
一行一个字符串 ans
,表示答案。
数据规模
0<k≤∣s∣≤5000000
样例输入
helloworld 5
样例输出
ellld
乍一看好像有点难,当看看样例就应该差不多知道了,我们直接求区间中最小的字符,然后将这个区间往后移动就好了。。。。当时AC最多的一题。我们设置head=1,tail=len(s)-k+1,然后在这里面找到最小字符输出,接着head接在这个最小字符的后面,tail++就可以继续找了,比较简单就不多说了。但注意的是这里的空间有点限制,所以开一颗线段树就好了,再开一颗会MLE,所以最好用树状数组。
当然官方题解是单调栈。。。这就非常快了:
设串长为 n,则只需删掉n-k 个字符。用一个单调栈维护,依次将字符串的每个字符插入,如果当前删掉的字符不足 n-k个并且栈顶 元素 插入的元素,那么删掉栈顶,直至删掉的字符达到n-k 或者满足单调栈的性质。 最后取栈里前k 个字符输出即可。
以下是AC代码:
线段树(常数有点大,900ms+):
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1
const int mac=5e6+10;
char s[mac];
int tree[mac<<2];
void build(int l,int r,int rt)
{
tree[rt]=999;
if (l==r) {
tree[rt]=s[l]-'a';
return;
}
int mid=(l+r)>>1;
build(lson);build(rson);
tree[rt]=min(tree[ls],tree[rs]);
}
int query(int l,int r,int rt,int L,int R)
{
int ans=999;
if (l>=L && r<=R) return tree[rt];
int mid=(l+r)>>1;
if (mid>=L) ans=min(ans,query(lson,L,R));
if (mid<R) ans=min(ans,query(rson,L,R));
return ans;
}
int main()
{
int k;
scanf ("%s",s+1);
scanf ("%d",&k);
int len=strlen(s+1);
build(1,len,1);
int head=1,tail=len-k+1,sum=0;
for (int i=1; i<=len; i++){
int p=query(1,len,1,head,tail);
printf ("%c",p+'a');
int j;
for (j=head; j<=tail; j++) if (s[j]=='a'+p) break;
head=j+1;tail++;
if (tail>len) tail=len;
sum++;
if (sum>=k) break;
}
printf ("\n");
return 0;
}
树状数组(常数比较小300ms+):
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mac=5e6+10;
char s[mac];
int tree[mac],a[mac];
int lowbit(int x){return x&-x;}
void update(int pos)
{
for (int i=1; i<lowbit(pos); i<<=1){
tree[pos]=min(tree[pos],tree[pos-i]);
}
}
int query(int l,int r)
{
int ans=999;
while (1){
ans=min(ans,a[r]);
if (r==l) break;
for (r--; r-lowbit(r)>=l; r-=lowbit(r))
ans=min(ans,tree[r]);
}
return ans;
}
int main()
{
int k;
scanf ("%s",s+1);
scanf ("%d",&k);
int len=strlen(s+1);
for (int i=1; i<=len; i++)
a[i]=tree[i]=s[i]-'a';
for (int i=1; i<=len; i++) update(i);
int head=1,tail=len-k+1,sum=0;
for (int i=1; i<=len; i++){
int p=query(head,tail);
printf ("%c",p+'a');
int j;
for (j=head; j<=tail; j++) if (s[j]=='a'+p) break;
head=j+1;tail++;
if (tail>len) tail=len;
sum++;
if (sum>=k) break;
}
printf ("\n");
return 0;
}