時限: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;
}