2021年度训练联盟热身训练赛第一场 E Early Orders 思维 + 栈

传送门

题意: n n n个数,一个 k k k,求 a a a中包含 1 − k 1-k 1k且字典序最小的子序列。

思路1: p [ i ] p[i] p[i] i i i出现的最后位置,让后维护一个栈,当这个数不在栈里时将其入栈,入栈的时候跟栈顶比较,当 a [ i ] < s t k [ t o p ] 且 p [ s t k [ t o p ] ] > i a[i]<stk[top] 且p[stk[top]]>i a[i]<stk[top]p[stk[top]]>i的时候弹出栈顶,即当这个数比栈顶小且后面还有栈顶元素可以替换他的时候出栈。这样最后栈中元素即为答案。
复杂度 O ( n ) O(n) O(n)

思路2: 用线段树维护区间中 a [ i ] a[i] a[i]值最小的位置,让后记录一下每个数最后出现的位置,一次找 k k k个数。每次查询的区间就是 [ p r e , s . b e g i n ( ) ] [pre,s.begin()] [pre,s.begin()],让后返回的位置即为当前选的数的位置,其中 s s s s e t set set,存每个数最后出现的位置, p r e pre pre是上次取的数的位置+1。来讨论一下这样为什么是正确的。首先我们要字典序最小,贪心的想肯定是前面越小越好,假设序列为 [ 4 , 4 , 2 , 1 , 3 , 4 , 1 ] , k = 3 [4,4,2,1,3,4,1],k=3 [4,4,2,1,3,4,1],k=3,初始的时候 p r e = 1 pre=1 pre=1 s . b e g i n ( ) = 3 s.begin()=3 s.begin()=3,让后我们找 [ 1 , 3 ] [1,3] [1,3]最小值的下标,为什么要在 [ 1 , 3 ] [1,3] [1,3]中找呢?因为 3 3 3位置是 2 2 2最后一次出现的位置,如果你跑 [ 1 , 4 ] [1,4] [1,4]中找的话,你会选到 1 1 1,这样你第一个数就是 1 1 1了,而且 p r e = 5 pre=5 pre=5,代表你之后都不会选到 2 2 2这个数了,所以要以最后出现的位置为界,来找前面出现的最小值。让后每次都找当前区间最小值最左边的位置,让后输出即可。

//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,k;
int a[N];
int stk[N],top;
int p[N],cnt[N];

int main()
{
    
    
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]]=i;
    for(int i=1;i<=n;i++)
    {
    
    
        if(cnt[a[i]]) continue;
        while(top&&stk[top]>a[i]&&p[stk[top]]>i) top--,cnt[stk[top+1]]=0;
        stk[++top]=a[i]; cnt[a[i]]=1;
    }
    for(int i=1;i<=top;i++) printf("%d ",stk[i]); puts("");





	return 0;
}
/*

*/



猜你喜欢

转载自blog.csdn.net/m0_51068403/article/details/114495423