2019計蒜之道複賽-D-星雲系統(線段樹|樹狀數組區間最值)

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章