jzoj 5573. 子序列
Sol :
经典的用优先队列求前𝑘大的题。 我们从小到大一个一个取出子序列。然后考虑如何进行拓展。 最开始我们肯定选择最小的数字,选完这个数字之后,我们有两种拓展方式,一种 是不选择这个数字,改为选择比它大的最小的数字(数字相同的位置越小的视为更小), 并且这个数字要在当前子序列的上一个元素之后,可以用主席树快速查找。第二种是强 制选择这个数字,并选择这个数字之后的最小的数字。 把所有可以拓展的状态都丢入堆中,现在最关键的问题是快速比较两个子序列的字 典序。肯定不能直接存整个子序列,但是注意到如果一个子序列出现了,那么它的所有 前缀也一定出现了,所以可以用Trie维护子序列,空间总复杂度是线性的。有了Trie树, 用lca就可以快速判断两个子序列的字典序了。
Code:
#include<bits/stdc++.h> using namespace std; #define sight(x) ('0'<=x&&x<='9') #define Mid (l+r>>1) #define M 2200001 #define Siz 100001 #define LL long long vector<int> V[Siz+7]; int siz[M],ls[M],rs[M],tot,Kb,pos,pos2,rt[Siz+7],n,a[Siz+7],P[Siz+7],Ha[Siz+7],Pos[M]; LL p,seed; template <class T> inline void read(T &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } void insert(int last,int &now,int l,int r,int pos,int pos2) { now=++tot; siz[now]=siz[last]+1; Pos[now]=pos2; if (l==r) return; if (pos<=Mid) rs[now]=rs[last],insert(ls[last],ls[now],l,Mid,pos,pos2); else ls[now]=ls[last],insert(rs[last],rs[now],Mid+1,r,pos,pos2); } void find(int last,int now,int l,int r,int k) { if (l==r) { pos=Pos[now]; return; } if (siz[ls[now]]-siz[ls[last]]>=k) find(ls[last],ls[now],l,Mid,k); else find(rs[last],rs[now],Mid+1,r,k-siz[ls[now]]+siz[ls[last]]); } int Find(int l,int r,int p){ return find(rt[n+1],rt[l+1],1,Siz,p),pos; } int tt,nxt[Siz+7],last[Siz+7]; void Sol(int l,int r) { int o=P[l]; for (int i=1;i<=n-o;i++) { int x=Find(o,n,i),la=tt,ww=0; for (int j=x;j;j=nxt[j]){ ww++; for (int k=l;k<=r;k++) { if (j<=P[k]) continue; P[++tt]=j; Ha[tt]=(1ll*Ha[k]*seed+a[j])%p; if (tt==Kb) { for (int ch=1;ch<=Kb;ch++) writeln(Ha[ch]); exit(0); } } } Sol(la+1,tt),i+=ww-1; } } signed main () { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); read(n); read(Kb); read(seed); read(p); for (int i=1;i<=n;i++) { read(a[i]); V[a[i]].push_back(i); nxt[last[a[i]]]=i; last[a[i]]=i; } for (int i=n;i;i--) insert(rt[i+1],rt[i],1,Siz,a[i],i); Sol(0,0); return 0; }